mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-07-14 19:27:09 +00:00
The suite runs all 7 packs' execution tiers against one shared backend locally (CI shards one backend per pack). Serial execution created three distinct cross-test contaminations that failed a different set of packs each run; each is now fixed at its mechanism: - Foreign execution noise: mount/persistence/wiring/T0/core-smoke tiers queue no prompts, yet caught a prior tier's async execution error (PromptExecutionError, a 400 on /api/prompt). isForeignExecutionNoise filters execution-domain console lines from the non-executing tiers only; the executing tiers still assert them. Same "not this test's evidence" principle as event attribution (ARCHITECTURE section 9). - Queue contention: the auto-run queue-busy guard hard-failed when a prior pack's slow CPU execution was still draining. drainUntilIdle waits it out (interrupt + clear + poll, throw-on-error so a failed read counts as busy); only a genuinely wedged backend fails. runBatch's post-timeout drain grows from 5s to 90s for the same reason. - Slow-under-load misread as a regression: the single-node disambiguation re-run gets 60s instead of the batch's 20s. A real hang still exceeds it. Also excludes the CLIPSeg model loaders (essentials, WAS) - model-download nodes, same non-interruptible class as the listed BLIP/SAM/MiDaS loaders. Reviewed by four-hat CORE (ship it); the new predicate is unit-pinned. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
83 lines
3.8 KiB
TypeScript
83 lines
3.8 KiB
TypeScript
// Pack-attributed console noise with no visible error surface. Shared by
|
|
// the all-nodes tiers and the curated run tier so one ledger covers every
|
|
// surface a pack's script can emit on. Filter-guarded: a pattern suppresses
|
|
// matching errors for its pack only; stale entries are caught by review,
|
|
// not observation (several patterns are environment-conditional, so
|
|
// observed-firing guards would false-fail - see ARCHITECTURE.md section 10).
|
|
export const CONSOLE_ERROR_ALLOWLIST: Record<
|
|
string,
|
|
Array<{ pattern: RegExp; reason: string }>
|
|
> = {
|
|
'ComfyUI-Impact-Pack': [
|
|
{
|
|
// Media/text widgets preview their value via root-relative URLs at
|
|
// creation; 404s on a backend whose root does not serve the file.
|
|
pattern:
|
|
/Failed to load resource.*404.*(example\.png|plain_video\.mp4|file\.txt)/,
|
|
reason: 'media widget previews its value via a root-relative URL'
|
|
},
|
|
{
|
|
// PreviewBridge widgets fetch their internal preview id on configure;
|
|
// a bare backend has no image behind it.
|
|
pattern: /Failed to load resource.*400.*api\/impact\/get\/pb_id_image/,
|
|
reason: 'PreviewBridge fetches its preview id on configure'
|
|
},
|
|
{
|
|
// The save/reload tier writes `<value>_cn` probe values; media widgets
|
|
// preview them as URLs and 404.
|
|
pattern: /Failed to load resource.*404.*_cn/,
|
|
reason: 'set-and-stick probe value previewed by a media widget'
|
|
}
|
|
],
|
|
'ComfyUI-KJNodes': [
|
|
{
|
|
// Image/video loader previews fetch their combo value at creation;
|
|
// on a backend with an empty input dir the value is undefined and the
|
|
// preview 404s (and retries with a fresh rand). Console-only noise,
|
|
// no visible error; upstream-report candidate.
|
|
pattern:
|
|
/Failed to load resource.*\/api\/view\?type=input&filename=undefined/,
|
|
reason: 'loader preview fetches undefined filename on empty input dir'
|
|
}
|
|
],
|
|
'ComfyUI-Custom-Scripts': [
|
|
{
|
|
// betterCombos.js:473 checks `typeof ret === "object" && "content" in
|
|
// ret`; typeof null is "object", so a null ret during save/reload
|
|
// throws `Cannot use 'in' operator to search for 'content' in null`
|
|
// as an uncaught page error - invisible until pageerror collection
|
|
// landed. Pack-owned and deterministic; upstream-report candidate.
|
|
pattern: /Cannot use 'in' operator to search for 'content' in null/,
|
|
reason: 'betterCombos.js missing null check throws during save/reload'
|
|
}
|
|
]
|
|
}
|
|
|
|
export function unallowlistedErrors(pack: string, errors: string[]): string[] {
|
|
const allowlist = CONSOLE_ERROR_ALLOWLIST[pack] ?? []
|
|
return errors.filter(
|
|
(error) => !allowlist.some((rule) => rule.pattern.test(error))
|
|
)
|
|
}
|
|
|
|
// Execution errors surface on the tiers that actually queue prompts (the
|
|
// curated run and the auto-run tier). The mount, persistence, and wiring
|
|
// tiers queue nothing, so a prompt-execution error arriving in their console
|
|
// collector is an async stray from a prior tier's still-draining execution -
|
|
// the same "not this test" principle the event-attribution filter uses
|
|
// (ARCHITECTURE section 9). It is filtered from the non-executing tiers only;
|
|
// the executing tiers still assert on it. This is not error suppression: the
|
|
// visible error SURFACES (overlay/dialog/toast) are still asserted separately
|
|
// by expectNoVisibleErrors.
|
|
const FOREIGN_EXECUTION_NOISE: RegExp[] = [
|
|
/PromptExecutionError/,
|
|
/Prompt execution failed/,
|
|
// The browser logs a rejected prompt submission as a failed resource load
|
|
// on /api/prompt. Only the executing tiers POST there, so this line in a
|
|
// mount/persistence/wiring collector is a prior tier's async submission.
|
|
/Failed to load resource.*\/api\/prompt/
|
|
]
|
|
export function isForeignExecutionNoise(error: string): boolean {
|
|
return FOREIGN_EXECUTION_NOISE.some((pattern) => pattern.test(error))
|
|
}
|