HH-415: preserve binary frame and baseline semantics

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
2026-08-21 14:42:38 +08:00
co-authored by multica-agent
parent d4b9c66629
commit aa48fd6943
5 changed files with 195 additions and 92 deletions
+11 -6
View File
@@ -601,9 +601,10 @@ export function eventCollector(sessionId, targetId, {
case "Network.webSocketFrameReceived": {
const direction = method.endsWith("Sent") ? "sent" : "received";
mark(`ws_${direction}`);
const payloadBytes = params.response.opcode === 2
const payloadBytes = Buffer.byteLength(params.response.payloadData);
const decodedPayloadBytes = params.response.opcode === 2
? Buffer.from(params.response.payloadData, "base64").length
: Buffer.byteLength(params.response.payloadData);
: payloadBytes;
let state = webSocketLimits.get(requestId);
if (!state) {
state = { window: null, windowEvents: 0, emitted: 0 };
@@ -616,11 +617,11 @@ export function eventCollector(sessionId, targetId, {
}
state.windowEvents++;
let dropReason;
if (payloadBytes > maxWebSocketFrameBytes) dropReason = "frame_size_limit";
if (decodedPayloadBytes > maxWebSocketFrameBytes) dropReason = "frame_size_limit";
else if (state.windowEvents > maxWebSocketEventsPerSecond) dropReason = "rate_limit";
else if (state.emitted >= maxWebSocketEventsPerConnection) dropReason = "event_limit";
if (dropReason) {
dropWebSocketFrame(requestId, dropReason, payloadBytes);
dropWebSocketFrame(requestId, dropReason, decodedPayloadBytes);
break;
}
state.emitted++;
@@ -629,6 +630,7 @@ export function eventCollector(sessionId, targetId, {
direction,
opcode: params.response.opcode,
payload_bytes: payloadBytes,
...(params.response.opcode === 2 && { decoded_payload_bytes: decodedPayloadBytes }),
payload: { state: "omitted", reason: "frame_policy" },
});
break;
@@ -704,7 +706,7 @@ function assertIsolation(records, sessions) {
}
}
async function main(attemptFailures = [], startup = { requested_samples: 1, successful_samples: 1, max_renderer_failure_rate: 1 }) {
async function main(attemptFailures = [], startup = { requested_samples: 1, successful_samples: 1, max_renderer_failure_rate: 1 }, resourceSamples = []) {
const binary = process.env.CLARK_BINARY_PATH;
assert(binary, "set CLARK_BINARY_PATH to the clark-browser Chromium binary");
const outputDir = path.resolve(process.env.M0_OUTPUT_DIR ?? "artifacts");
@@ -804,6 +806,7 @@ async function main(attemptFailures = [], startup = { requested_samples: 1, succ
const resources = await processBaseline(browserPid, resourceSampleCount, resourceSampleIntervalMs);
assert(resources.rss_kib.max <= maxRssKib, `browser RSS ${resources.rss_kib.max} KiB exceeds ${maxRssKib} KiB`);
assert(resources.process_count.max <= maxProcessCount, `browser process count ${resources.process_count.max} exceeds ${maxProcessCount}`);
resourceSamples.push({ sample: startup.successful_samples, resources });
browserClient = await new CDP(version.webSocketDebuggerUrl).connect();
await browserClient.call("Target.closeTarget", { targetId: page.id });
await cdp.closed;
@@ -866,6 +869,7 @@ async function main(attemptFailures = [], startup = { requested_samples: 1, succ
sensitive_body_redaction: "pass",
},
resources,
resource_samples: resourceSamples,
resource_thresholds: { max_rss_kib: maxRssKib, max_process_count: maxProcessCount, conclusion: "within_threshold" },
startup: {
...startup,
@@ -896,6 +900,7 @@ async function main(attemptFailures = [], startup = { requested_samples: 1, succ
async function runSpike() {
const failures = [];
const resourceSamples = [];
const startup = {
requested_samples: Number(process.env.M0_STARTUP_SAMPLES ?? 3),
successful_samples: 0,
@@ -907,7 +912,7 @@ async function runSpike() {
for (let attempt = 1; attempt <= 3; attempt++) {
startup.successful_samples = sample;
try {
await main(failures, startup);
await main(failures, startup, resourceSamples);
break;
} catch (error) {
const original = error.cause ?? error;