fix(qa): give the canonical lane meaningful inputs for six tools (#703)

On a bundles-installed container the canonical lane reported six false
failures, all harness gaps rather than product bugs:

- remove-gif-background got a still GIF and correctly refused it; pin the
  animated fixture it actually needs.
- erase-object got no mask part, so the route's 400 was correct; wire the
  mask through SECONDARY_INPUTS the way the other multi-input tools are.
- passport-photo's base route refuses by design (use /analyze or /generate);
  record that in EXPECTED_SELF_REJECT.
- ocr, transcribe-audio and auto-subtitles ran on fixtures carrying none of
  the text or speech they extract, so they emitted empty but valid artifacts
  the oracle read as zero-byte failures. Pin fixtures that carry real content.

Verified red to green against a live v2.2.0 container with every bundle
installed: the six went from 6 fail to 5 pass plus 1 expected-reject, the
multi lane stayed clean (0 fail across 20 tools), and a direct probe showed
the download path was never at fault (ocr on a text-free image returns a
correct 0-byte result; on ocr-clean.png it returns the real text).

Fixes #690
This commit is contained in:
SnapOtter
2026-07-31 15:06:24 +08:00
committed by GitHub
parent ae56a0ab7a
commit 447190afda
+22
View File
@@ -146,6 +146,10 @@ interface SecondarySpec {
const SECONDARY_INPUTS: Record<string, SecondarySpec[]> = {
"watermark-image": [{ field: "watermark", ext: ".png", modality: "image" }],
compose: [{ field: "overlay", ext: ".png", modality: "image" }],
// erase-object needs a mask image as a discrete second file; without it the
// route refuses with 400. The worker resizes the mask to the image, so any
// valid PNG works.
"erase-object": [{ field: "mask", ext: ".png", modality: "image" }],
compare: [{ field: "file", sameAsPrimary: true }],
"find-duplicates": [{ field: "file", sameAsPrimary: true }],
collage: [{ field: "file", sameAsPrimary: true }],
@@ -175,6 +179,16 @@ const EXTRA_FIELDS: Record<string, Record<string, string>> = {
const TOOL_FIXTURES: Record<string, Record<string, string>> = {
"chart-maker": { ".json": join(REPO, "tests/fixtures/data/valid/chart.json") },
"extract-subtitles": { ".mkv": join(REPO, "tests/fixtures/video/formats/tiny-subs.mkv") },
// remove-gif-background rejects a still GIF by design; it needs an animated one.
"remove-gif-background": {
".gif": join(REPO, "tests/fixtures/image/valid/animated-simpsons.gif"),
},
// Extraction tools emit an empty (but valid) artifact when the input has none
// of the thing they extract, which the decodable-output oracle then reads as a
// zero-byte failure. Pin fixtures that actually carry text and speech.
ocr: { ".png": join(REPO, "tests/fixtures/image/valid/ocr-clean.png") },
"transcribe-audio": { ".wav": join(REPO, "tests/fixtures/audio/valid/speech-10s.wav") },
"auto-subtitles": { ".mp4": join(REPO, "tests/fixtures/video/valid/speech-10s.mp4") },
};
/**
@@ -184,6 +198,11 @@ const TOOL_FIXTURES: Record<string, Record<string, string>> = {
*/
const CANONICAL_EXT: Record<string, string> = {
"extract-subtitles": ".mkv",
// ocr and transcribe-audio declare several formats but only the pinned
// content fixture above exercises them, so force its extension over the
// earlier-declared .jpg / .mp3 that would resolve to a content-free file.
ocr: ".png",
"transcribe-audio": ".wav",
};
/** Formats a multi-input tool only accepts on its SECONDARY field. */
@@ -231,6 +250,9 @@ const EXPECTED_SELF_REJECT: Record<string, RegExp[]> = {
"remove-pages": [/out of range/i, /only \d+ page/i],
"extract-pages": [/out of range/i, /only \d+ page/i],
"split-pdf": [/out of range/i, /only \d+ page/i, /single page/i],
// The base passport-photo route is a dispatcher; the real work lives on its
// /analyze and /generate sub-routes, so the bare tool path refuses by design.
"passport-photo": [/\/analyze or \/generate/i],
};
/** High-risk axis triples worth explicit three-way coverage. */