tool/endpoint: validate_workflow (and run_workflow's matching gate)
workspace: qa-ep12
Summary
The H3 num_frames bound (17*n+5, 124–345, rounds up) that #96 added is enforced only when the
frame count is a top-level workflow variable. When the same value sits in a list-entry field
— shots[].num_frames in templates/minimax/dialogue-short — no bound is checked, no rounding
warning is emitted, and the run is quoted and accepted.
This is the exact regression #96 was closed to prevent, and the value below is the one
validate_workflow's own tool description cites as the motivating example:
H3's frame count has to be 17 * n + 5 between 124 and 345, and 61 used to validate and then
fail 138 s into the run, after the weights were loaded.
61 still validates — it just has to be spelled as a list entry.
repro
Both calls made over MCP, workspace qa-ep12, dw 0.4.0-beta.4 on lem. Neither costs GPU time.
A — list-entry field, num_frames: 61 → accepted:
validate_workflow(
name="templates/minimax/dialogue-short",
workspace="qa-ep12",
arguments={"shots": [{"name": "probe", "num_frames": 61,
"references": [{"reference_type": "diffusers.modular_pipelines.minimax_h3.MiniMaxH3ImageReference",
"from_file": "asset:qa-cast/hal-portrait.jpg"}],
"prompt": "<a minimal but well-formed H3 ref2va prompt>"}]})
response:
{"valid": true, "error": null, "errors": [], "warnings": [],
"checked_arguments": ["shots"],
"plan": {"steps": 2, "list_entries": {"shots": 1},
"estimate": {"minutes": 8.4, "basis": "derived", "device": "cuda", "partial": false}}}
B — top-level variable, num_frames: 61, same server, same workspace → refused:
validate_workflow(name="templates/minimax/music-video", workspace="qa-ep12",
arguments={"num_frames": 61})
response:
{"valid": false,
"errors": [{"path": "arguments.num_frames",
"message": "'num_frames' is 61 (rounds up to 73), which this workflow does not accept: must be at least 124. Accepted: 124 to 345, 17 * n + 5 ... The rule is declared on the workflow, so it is checked before anything loads rather than after the weights are in memory"}]}
C — the rounding warning is missing too. The same dialogue-short call with a legal-range but
off-grid shots[1].num_frames: 130 (→ 141) validates "warnings": []. As a top-level variable this
is documented to come back as a warning naming what the value becomes. In a list entry the caller is
told nothing, so a deliverable that is silently 141 frames instead of 130 is discovered by measuring
the output — which is what #96 removed the need to do.
expected
shots[].num_frames is checked against the same declared bound as a top-level num_frames:
- 61 → error at
arguments.shots[0].num_frames, no plan handed back, and run_workflow refuses
at the same gate.
- 130 → warning naming 141, at the same path.
More generally: a bound declared for a variable should follow the value into a list-entry field that
feeds the same pipeline argument, since list_workflows' lists block already tells a caller that
shots[] carries num_frames and nothing there says the rule stops applying.
actual
Both are accepted silently, with a cost estimate (8.4 min for the single-shot case) attached.
notes
get_workflow("templates/minimax/dialogue-short", variables_only=true) reports no constraints
block, and the compact list_workflows(shape="sequence") entry for it likewise has no constraints
— where templates/minimax/music-video has {"num_frames": "17*n+5, 124-345, rounds up"}. So the
template arguably never declares the bound in the first place; if the fix is to declare it on the
list field rather than to propagate it, the discovery surface needs to report it there too, or a
caller reading constraints still can't find the rule.
I did not spend the GPU run to observe the downstream failure — the free validate-side asymmetry
is the whole repro, and burning ~8 min of 3090 to watch a load-then-fail is the cost the bound
exists to avoid. Say the word if you want the run-time half confirmed and I'll take it next cycle.
Found while running TESTER_TASK.md (authoring ep12). Reported by the tester agent running as
model opus via the anthropic provider.
tool/endpoint:
validate_workflow(andrun_workflow's matching gate)workspace:
qa-ep12Summary
The H3
num_framesbound (17*n+5, 124–345, rounds up) that #96 added is enforced only when theframe count is a top-level workflow variable. When the same value sits in a list-entry field
—
shots[].num_framesintemplates/minimax/dialogue-short— no bound is checked, no roundingwarning is emitted, and the run is quoted and accepted.
This is the exact regression #96 was closed to prevent, and the value below is the one
validate_workflow's own tool description cites as the motivating example:61 still validates — it just has to be spelled as a list entry.
repro
Both calls made over MCP, workspace
qa-ep12, dw0.4.0-beta.4onlem. Neither costs GPU time.A — list-entry field,
num_frames: 61→ accepted:response:
{"valid": true, "error": null, "errors": [], "warnings": [], "checked_arguments": ["shots"], "plan": {"steps": 2, "list_entries": {"shots": 1}, "estimate": {"minutes": 8.4, "basis": "derived", "device": "cuda", "partial": false}}}B — top-level variable,
num_frames: 61, same server, same workspace → refused:response:
{"valid": false, "errors": [{"path": "arguments.num_frames", "message": "'num_frames' is 61 (rounds up to 73), which this workflow does not accept: must be at least 124. Accepted: 124 to 345, 17 * n + 5 ... The rule is declared on the workflow, so it is checked before anything loads rather than after the weights are in memory"}]}C — the rounding warning is missing too. The same
dialogue-shortcall with a legal-range butoff-grid
shots[1].num_frames: 130(→ 141) validates"warnings": []. As a top-level variable thisis documented to come back as a warning naming what the value becomes. In a list entry the caller is
told nothing, so a deliverable that is silently 141 frames instead of 130 is discovered by measuring
the output — which is what #96 removed the need to do.
expected
shots[].num_framesis checked against the same declared bound as a top-levelnum_frames:arguments.shots[0].num_frames, noplanhanded back, andrun_workflowrefusesat the same gate.
More generally: a bound declared for a variable should follow the value into a list-entry field that
feeds the same pipeline argument, since
list_workflows'listsblock already tells a caller thatshots[]carriesnum_framesand nothing there says the rule stops applying.actual
Both are accepted silently, with a cost estimate (8.4 min for the single-shot case) attached.
notes
get_workflow("templates/minimax/dialogue-short", variables_only=true)reports noconstraintsblock, and the compact
list_workflows(shape="sequence")entry for it likewise has noconstraints— where
templates/minimax/music-videohas{"num_frames": "17*n+5, 124-345, rounds up"}. So thetemplate arguably never declares the bound in the first place; if the fix is to declare it on the
list field rather than to propagate it, the discovery surface needs to report it there too, or a
caller reading
constraintsstill can't find the rule.I did not spend the GPU run to observe the downstream failure — the free validate-side asymmetry
is the whole repro, and burning ~8 min of 3090 to watch a load-then-fail is the cost the bound
exists to avoid. Say the word if you want the run-time half confirmed and I'll take it next cycle.
Found while running
TESTER_TASK.md(authoring ep12). Reported by the tester agent running asmodel opus via the anthropic provider.