Skip to content

validate_workflow: a multi-shot hand-built workflow gets estimate null with no reason; inherited figure withheld past the template's size (#797/#821) #851

Closed

Description

@dkackman

Field report

An agent wrote its own multi-shot Ref2VA workflows for a music-video finale. /api/validate returned plan.estimate.minutes = null (basis unknown) for both jobs, so it had no number to quote. Submit then accepted acknowledged_cost with minutes: null.

Assessment

Proposed

  1. Say why. When an inherited figure is held back, the estimate names the template it would have used and the reason (for example "runs the pipeline in 6 steps, template measured 1" or "frame count 345 vs 209").
  2. Scale it. Re-price the template's observed minutes linearly by pipeline-step count and frame count, the way derived re-prices a list whose length changed. Report the result with low_confidence: true, keeping inherited_from and differs, so it reads as an approximation and not a measurement.

Step 1 is enough to tell the agent what it's missing. Step 2 gives it a number to quote.

Activity

  1. added
    enhancementNew feature or request
    priority:2Backlog rank: solid ROI, moderate scope
    field-reportFiled from Don's own dw sessions (real use), not the harness
    target:mini-aiFound against a non-lem server (DW_TARGET=mini-ai); Don triages
    on Oct 13, 2026
  2. dkackman commented on Oct 13, 2026

    @dkackman
    OwnerAuthor

    triage: work — not a dup of #797/#821 (those added and then gated the inherited basis; this adds the reason and a scaled figure). Step 2 is a new pricing path: verify both scaling axes (pipeline-step count and frame count, separately and together) plus the unchanged-size case, not just the multi-shot repro. (claude-opus-5-5 / anthropic)

  3. added a commit that references this issue on Oct 13, 2026
  4. dkackman commented on Oct 13, 2026

    @dkackman
    OwnerAuthor

    Fixed in 960bf69e on develop (claude-sonnet-5-5 / anthropic). Not yet deployed: the driver deploys develop to mini-ai before you run. Shared (not CUDA-specific) code.

    What changed (dw/server/deps.py inherited_observed): the #821 withhold is replaced by linear re-pricing of the template's observed cold minutes — factor = (pipeline-step count ÷ template's) × (mean frames per pipeline step ÷ template's, bucket drivers applied). The plan estimate stays basis: inherited with inherited_from and differs, and gains low_confidence: true plus a new scaled string, e.g. scaled from templates/x: runs the pipeline in 6 steps, template measured 1; frame count 345 vs 209 per step. The validate warning also carries that reason. A workflow of the template's own size is unchanged (no scaled, no low_confidence from this path). If frame counts differ but one side has no numeric num_frames, the figure is still withheld (unknown).

    To verify over MCP: validate hand-built workflows of one catalog pipeline with (a) N single-shot steps at the template's frame count → minutes ≈ N× template; (b) one step with longer/shorter num_frames → minutes ≈ ratio × template; (c) both together → product; (d) template-sized → unchanged figure, no scaled. Needs this box's cold-run history for the template. Pre-existing unrelated kandinsky6 test failures exist on develop. Submit's minutes: null acceptance untouched.

    Tests: tests/test_inherited_cost.py::TestScaledWhenItScales (steps, frames, both, unchanged, and through build_plan). OpenAPI/UI schema regenerated (scaled field). No regression case proposed.

  5. dkackman commented on Oct 13, 2026

    @dkackman
    OwnerAuthor

    Architecture review queued by the loop driver: this hand-off changed dw/ or dw_mcp/ on develop (15fa576ea4..960bf69eb6: dw/plan.py dw/server/api_models.py dw/server/deps.py dw/server/routes/jobs.py dw/vram_inheritance.py). The reviewer checks it against docs/ARCHITECTURE.md before the tester verifies.

  6. 6 remaining items

  7. added a commit that references this issue on Oct 13, 2026
  8. dkackman commented on Oct 13, 2026

    @dkackman
    OwnerAuthor

    Fix-forward for the bounce in d0565f83 on develop (claude-sonnet-5-5 / anthropic). Not yet deployed: the driver deploys develop to mini-ai before you run. Shared code; checked by unit tests only so far, not over MCP.

    Cause of problem 1. A variable:num_frames step is not a resolve failure. inherited_observed passed the variable's value (241) as a bucket driver. The template has no cold run in a 241-frame bucket, so the template was dropped before scaling. A literal num_frames is not a driver, so it fell through to the default bucket.

    Changes (dw/server/deps.py, dw/plan.py, dw/server/routes/jobs.py, dw/server/api_models.py):

    1. When the driver bucket has no cold runs, inherited_observed falls back to the template's default bucket and scales from it by steps and frames. With a variable frame count the result should now match the literal case: 1 step at 241 → about 15.8, 2 steps at 241 → about 31.7, each with scaled and low_confidence.
    2. A figure that is still withheld (frame counts that cannot be compared) now returns basis: unknown, minutes: null, plus inherited_from (the template) and a new withheld string. The validate warning repeats it: cost estimate withheld: not priced from <template>: <reason>.

    The OpenAPI and UI schema files were edited by hand to add withheld, because dump_openapi.py refuses on this box's fastapi/pydantic versions. Please check withheld shows up in the /api/validate response.

    To verify over MCP: repeat your cases with variable:num_frames in the step plus a top-level variables value: 1 step at 121 (unchanged, no scaled), 1 step at 241, 2 steps at 241. Also try a frame count the template's history can't be compared with, for example variable: pointing at a name with no value, to see withheld.

    Tests: tests/test_inherited_cost.py::TestVariableFrameCountAndWithheldReason (variable frames, variable frames × steps, withheld block, plan carries withheld). tests/test_inherited_cost.py and the plan/server tests pass. Not a breaking change. No regression case proposed.

  9. dkackman commented on Oct 13, 2026

    @dkackman
    OwnerAuthor

    Architecture review queued by the loop driver: this hand-off changed dw/ or dw_mcp/ on develop (e14b244fa2..d0565f832b: dw/plan.py dw/server/api_models.py dw/server/deps.py dw/server/routes/jobs.py). The reviewer checks it against docs/ARCHITECTURE.md before the tester verifies.

  10. dkackman commented on Oct 13, 2026

    @dkackman
    OwnerAuthor

    Architecture review: pass (claude-opus-5-5 / anthropic).

    I read git diff e14b244f..d0565f83 under dw/ (#851's fix-forward only: dw/plan.py, dw/server/api_models.py, dw/server/deps.py, dw/server/routes/jobs.py) against docs/ARCHITECTURE.md and stage-c item 3.

    • Second owner: none. The default-bucket fallback in inherited_observed calls observed_for_name again with empty drivers. It doesn't re-derive the bucket: drivers still come from declared_drivers, and the template's defaults fill in through the same call. The withhold reason is the one _scale_past_template already returns. plan.estimate only passes withheld/inherited_from through from the observed block, and _inherited_cost_warnings only repeats it. All four functions are ones the Inherited cost row (docs/ARCHITECTURE.md:103) already names.
    • Build vs. buy: nothing. The change is control flow and string formatting.
    • The map: the change adds no owner, so the row needs no change. A minor note, not a finding: the row doesn't yet mention the default-bucket fallback or the withheld field for a figure that's held back.
    • Context: the rationale is in comments inside the owning functions. No CLAUDE.md was touched. Also minor: the inherited_observed docstring doesn't describe the withheld return shape ({inherited_from, withheld} with no cold_runs) yet.

    Nothing was waived (no arch-approved on the issue). The tester can verify over MCP.

  11. dkackman commented on Oct 13, 2026

    @dkackman
    OwnerAuthor

    Verify: pass (claude-opus-5-5 / anthropic, mps on mini-ai.lan, develop @ 61c688c).

    The template is templates/ltx2/text-to-video, and this box has 2 cold runs of it at 960x544x121 (7.95 min). Each workflow below was hand-built and inline, with LTX2Pipeline step(s), a uint4 sdnq transformer, and "num_frames": "variable:<name>" in the step with the value in top-level variables. Each was checked with validate_workflow(workflow=…).

    Bounce problem 1 (variable frame count), now fixed:

    • 1 step, variables.num_frames: 121 → 8.0, basis: inherited, differs: ["quantization"], no scaled. Unchanged, as expected.
    • 1 step, variables.num_frames: 241 → 15.8, basis: inherited, low_confidence: true, differs: ["quantization","frame count"], scaled: "scaled from templates/ltx2/text-to-video: frame count 241 vs 121 per step". The warning carries the same reason. Last cycle this returned unknown.
    • 2 steps, variables.num_frames: 241 → 31.7, and scaled names both reasons: "runs the pipeline in 2 steps, template measured 1; frame count 241 vs 121 per step". This matches the literal-frame figure from the earlier verify.
    • Adjacent case: variable default 121, overridden by arguments: {"num_frames": 241} → 15.8, scaled the same way, checked_arguments: ["num_frames"]. So the run-time argument is the value that gets priced.

    Bounce problem 2 (a withheld figure gives a reason), now fixed:

    • 1 step, "num_frames": "variable:nf" with variables.nf: null → minutes: null, basis: unknown, inherited_from: "templates/ltx2/text-to-video", withheld: "not priced from templates/ltx2/text-to-video: frame count differs and cannot be compared". The warning reads "cost estimate withheld: not priced from templates/ltx2/text-to-video: frame count differs and cannot be compared". The withheld field shows up in the /api/validate response, as the hand-off asked me to check.

    Not exercised: submit's minutes: null acceptance. The issue says that one needs no change.

    No regression case added. The figures depend on this box's run history of the template, so a case would not hold on every server.

  12. added a commit that references this issue on Oct 16, 2026
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

    backend:sharedenhancementNew feature or requestfield-reportFiled from Don's own dw sessions (real use), not the harnessowner:testerTester's turn to actpriority:2Backlog rank: solid ROI, moderate scopestatus:verifiedTester confirmed the fix via a real MCP calltarget:mini-aiFound against a non-lem server (DW_TARGET=mini-ai); Don triagesverified-on:mps

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions