Files
workinf_Blender_Wasm/tools/web/wbv2-batch-contract.mjs
mes123456 b28b365f3a
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled
perf(web): add idempotent batch verification fast paths
2026-09-03 20:29:51 +08:00

61 lines
2.7 KiB
JavaScript

import crypto from "node:crypto";
export const COMMAND_BUDGET = Object.freeze({
maxCommands: 48,
maxReadCommands: 16,
});
/** Return the explicit source/RNA record IDs selected for one module batch. */
export function selectedRecordIds(module = {}) {
const values = module.selectedRecordIds ?? module.coverageBindings ?? module.sourceUnits ?? [];
return [...new Set((Array.isArray(values) ? values : []).filter((value) => typeof value === "string" && value.length > 0))];
}
/** A batch identity is stable across retries and changes when selection changes. */
export function batchIdFor(task, module = {}) {
const ids = selectedRecordIds(module);
const moduleId = module.moduleId ?? "UNKNOWN_MODULE";
const digest = crypto.createHash("sha256").update(JSON.stringify(ids)).digest("hex").slice(0, 16);
return module.batchId ?? `${task}:${moduleId}:${digest}`;
}
export function batchContract(task, module = {}) {
const selected = selectedRecordIds(module);
return {
batchId: batchIdFor(task, module),
selectedRecordIds: selected,
selectedCount: selected.length,
};
}
export function completedBatch(manifest, task, module = {}) {
const expected = batchContract(task, module);
return manifest?.status === "done"
&& manifest.batchId === expected.batchId
&& JSON.stringify(manifest.selectedRecordIds ?? []) === JSON.stringify(expected.selectedRecordIds);
}
export function commandBudget(commands = []) {
const values = Array.isArray(commands) ? commands.filter((value) => typeof value === "string") : [];
const readCommands = values.filter((value) => /\b(?:cat|head|tail|sed|rg|find|ls|stat)\b/u.test(value));
return {
maxCommands: COMMAND_BUDGET.maxCommands,
maxReadCommands: COMMAND_BUDGET.maxReadCommands,
commandCount: values.length,
readCommandCount: readCommands.length,
withinBudget: values.length <= COMMAND_BUDGET.maxCommands && readCommands.length <= COMMAND_BUDGET.maxReadCommands,
};
}
export function adaptiveBatchSize({ currentSize, history = [], minSize = 1, maxSize = currentSize, remaining = Number.MAX_SAFE_INTEGER }) {
const size = Math.max(minSize, Math.min(maxSize, currentSize));
const recent = history.filter((item) => Number.isFinite(item.durationMs) && Number.isFinite(item.commands)).slice(-3);
let next = size;
if (recent.some((item) => item.timeout === true || item.durationMs > 900_000 || item.commands > COMMAND_BUDGET.maxCommands)) {
next = Math.floor(size / 2);
} else if (recent.length > 0 && recent.every((item) => item.durationMs < 300_000 && item.commands < 24 && item.focusedGateFailure !== true)) {
next = size + 4;
}
return Math.max(minSize, Math.min(maxSize, remaining, next));
}