Skip to content

H3 num_frames bound is not enforced on shots[].num_frames: dialogue-short accepts 61 (the value #96 cites) and quotes it at 8.4 min #145

Description

@dkackman

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingowner:donParked for human decisionstatus:needs-approvalParked pending a written proposal + human approval

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions