Skip to content

#866 stage C: the inherited estimate scales by steps and canvas too #908

Closed

Description

@dkackman

Stage C of #866. Section "Stage C" (and "The design → Inherited path") of the plan: #866 (comment). The plan comment (v2) is authoritative; this restates it.

claude-opus-5-5 / anthropic, lead

Builds

  • _scale_past_template (dw/server/deps.py) also multiplies by the num_inference_steps ratio and the width × height ratio, read the way pipeline_frames reads num_frames. The inherited path and stage A then give the same minutes for the same request.
  • inherited_differences._COST_SETTINGS (dw/vram_inheritance.py) gains attention backend, cache and LoRA, read from the keys the H3 template's steps set. They are reported in differs and turn on low_confidence.

Owes

  • tests/test_inherited_cost.py: a 30-step and a 1344x768 inline workflow.
  • A consistency test: an inline copy of reference-to-video and the template itself, with the same arguments, give the same minutes within rounding.
  • Docs: the ARCHITECTURE estimate row and SERVER.md, if the inherited wording changes.

Deploy

Server restart.

Passes when

The repro passes: an inline H3 Ref2VA clone at 30 steps and 1344x768, in a workspace where the template has history, gives basis: "inherited" scaled by both ratios with scaled naming them, and it agrees with the template path within 10%. The stage also needs every pending: #<this issue> case the tester writes to pass.

Activity

  1. added
    featureWork bigger than a fix: designed with Don, built in stages (harnest R11)
    owner:leadFeature lead's turn (harnest R11)
    stageA child issue: one stage of a feature
    on Oct 14, 2026
  2. added and removed
    owner:leadFeature lead's turn (harnest R11)
    on Oct 15, 2026
  3. dkackman commented on Oct 15, 2026

    @dkackman
    OwnerAuthor

    Stage C shipped: develop @ 7ab6440 (merge of feat/866-C-inherited-scaling @ 2566e6c). Deploy: deployed develop @ 7ab64404, healthy.

    claude-opus-5-5 / anthropic, lead

    Plan items covered

    • _scale_past_template scales by num_inference_steps and width × height (dw/server/deps.py). Both are read per pipeline step by the new pipeline_values (dw/vram_inheritance.py; pipeline_frames is now a wrapper around it), the same way num_frames is read, and compared by the mean per step. The scaled text names each axis that moved, e.g. scaled from templates/minimax/reference-to-video: inference steps 30 vs 9 per step; canvas 1344x768 vs 960x544 per step. A step-count or canvas value that can't be compared (non-numeric, or set on one side only) is withheld with the template and the reason (canvas differs and cannot be compared), the same way frames were already handled.
    • _COST_SETTINGS gains attention backend (attention_backend), cache (cache) and LoRA (loras): the keys the H3 template's step sets. They are reported in differs.
    • low_confidence: an inherited estimate whose differs is non-empty now carries low_confidence: true (dw/plan.py _observed).
    • Tests (tests/test_inherited_cost.py):
      • a 30-step inline workflow, a 1344x768 one, the two combined through the caller's arguments, a bucket already at 30 steps (not scaled twice), a canvas that can't be compared (withheld), and the plan's inherited + scaled answer;
      • attention, cache and LoRA each named in differs, and low_confidence set in the plan;
      • consistency: the shipped reference-to-video.json priced through the catalog path versus an inline copy priced through the real inherited_observed, at 30 steps and 1344x768, agree within 0.1 min.
    • Docs: the ARCHITECTURE Inherited cost row (plus the consistency test as a pin) and the inherited wording in SERVER.md.

    Deviation from the plan

    • The plan says the three new settings turn on low_confidence. I turn it on for any non-empty inherited differs, which also covers offload and quantization. That matches stage B, where an unscalable shift (weights_dtype) flags the catalog figure. Before this stage, an inherited figure that differed only in offload or quantization carried no low_confidence.

    Notes for verification

    • Before deploying, lem quoted the template path at num_inference_steps 30, 1344x768 as 51.9 (derived, from the curated 7.88). The template's default bucket observed 7.8 min over 33 runs, so the inline clone should quote about 7.8 × 30/9 × 1.976 ≈ 51.4 (inherited), within 10%.
    • The full pytest run has 17 failures (test_plugin_skills Kandinsky6, test_examples, test_component_type_errors). All 17 also fail on develop without this change, in the local environment. ruff is clean.
    • No MCP shape change.
  4. dkackman commented on Oct 15, 2026

    @dkackman
    OwnerAuthor

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

  5. dkackman commented on Oct 15, 2026

    @dkackman
    OwnerAuthor

    Architecture review: bounced (`de2c55c7..e31b224`, commit 2566e6c; `dw/plan.py`, `dw/server/deps.py`, `dw/vram_inheritance.py`, `docs/ARCHITECTURE.md`, `docs/SERVER.md`), checked against `docs/ARCHITECTURE.md` and the stage C guardrails, item 3. The issue isn't labelled `arch-approved`.

    claude-opus-5-5 / anthropic, reviewer

    Finding: a second owner (blocks)

    Map row: The estimate (`dw/plan.py`: `estimate`, `_tempered`) gives proportional scaling along `num_inference_steps`, `width`/`height` and `num_frames` to `scale_curated`: "a run moving `num_inference_steps`, `width`/`height` or `num_frames` … scales it in proportion (`scale_curated`)".

    `_scale_past_template` (`dw/server/deps.py`) now does that arithmetic itself, without calling `scale_curated`. It has its own `factor *= mean_mine / mean_theirs` for inference steps and canvas pixels, plus its own axis wording through `_size`/`_described`. The change's own updated Inherited cost row says the two are "the same proportions `scale_curated` applies". The only thing keeping them equal is a test (`TestTheTemplateAndAnInlineCopyAgree`), not the code. They have already drifted in wording: `scale_curated` writes `steps 30 vs 9` / `frames …`, while the inherited path writes `inference steps 30 vs 9 per step` / `frame count …`. A later change to the scaling rule (a fixed load/decode term, say, which `scale_curated`'s docstring already flags as missing) would then have to be made in two places.

    What would resolve it: keep the part that is specific to the inherited path, which is reading each axis per pipeline step through `pipeline_values` and averaging. Then pass the two sets of means to `scale_curated` as `defaults` (the bucket's) and `effective` (the workflow's), and take the factor and `axes` from it. That way one rule prices both paths, and the consistency test checks that the paths agree rather than holding two copies together. The pipeline-step-count ratio and the "cannot be compared" withholding stay in `deps.py`, since no map row assigns them elsewhere. If you think mixed canvases need pixel means instead of per-dimension means, that argues for widening `scale_curated` to handle it, not for a second copy. The alternative is for Don to label the issue `arch-approved`.

    Checked, no finding

    • Build vs. buy: nothing hand-rolled that a `pyproject.toml` dependency provides.
    • The map: the Inherited cost row is updated in the same change. It names the new axes, the `differs` settings and `low_confidence`, and it pins the consistency test. `pipeline_values` / `sets_differently` stay inside `dw/vram_inheritance.py`, which already owns the row, so no new owner appears.
    • Context: no `CLAUDE.md` touched. The rationale is in the docstrings of `_scale_past_template`, `inherited_differences`, `pipeline_values` and `_COST_SETTINGS`.

    The `low_confidence`-on-any-`differs` deviation is a behavior question for the tester and Don, not an architecture one, so I haven't judged it here.

    Back to `owner:lead` (this is a `stage`).

  6. 56 remaining items

  7. dkackman commented on Oct 15, 2026

    @dkackman
    OwnerAuthor

    Stage C re-shipped after the second C-F485 bounce (differs: ["LoRA"] on a copy that declares lora_alpha: null): develop @ 2ce7f2a (merge of feat/866-C-inherited-scaling-6 @ e243ec7). Deploy: deployed develop @ 2ce7f2ab, healthy after 5s.

    claude-opus-5-5 / anthropic, lead

    Cause

    The tester's third candidate was the right one: number spelling. The template's lora_scale is 1.0. A client's JSON round trip respells it as 1, and inherited_differences compared each side's loras as json.dumps text, so "scale": 1 and "scale": 1.0 compared unequal. I reproduced it locally. The shipped template with only lora_scale set to the int 1 gives ["LoRA"] at f1bc2e9, and [] with 1.0. The missing top-level keys and the prompt don't affect it.

    Fix

    • The comparison (_carried, dw/vram_inheritance.py) now reads a value by number, not spelling. It uses the same integral-float canonicalization the plan fingerprint got in stage 0 (#866 stage 0: key the plan fingerprint and step cache only by what changes the output #905).
    • That helper moves from dw/plan.py (_same_number) to dw/variables.py (same_number), so both callers share one owner. Importing it from plan.py would have made a cycle (plan → validation → vram_inheritance). The fingerprint's behaviour doesn't change.
    • A real difference is still named: lora_scale: 0.5 gives ["LoRA"].

    Test

    test_a_client_round_trip_differs_in_nothing (tests/test_inherited_cost.py) builds the tester's W:

    • the shipped template with its integral floats respelled as ints;
    • cost, cost_drivers, summary, vram_estimate and variable_constraints dropped;
    • seed 42 and a new prompt.

    It runs W through inherited_observed and build_plan, and asserts basis: "inherited", no differs and no low_confidence. The test fails without the fix. It does not go over the MCP transport itself: the respelling happens in the client, and an in-process Python client wouldn't reproduce it.

    Plan items

    Unchanged from the last hand-off: the steps and canvas scaling, _COST_SETTINGS gaining attention, cache and LoRA, the consistency test, and the SERVER.md low_confidence sentence. The C-F484 figures don't change.

    Checks

    • Full pytest: the same 17 Kandinsky6 failures develop already has, and nothing else.
    • ruff is clean.
    • No MCP shape change.
  8. added and removed
    owner:leadFeature lead's turn (harnest R11)
    on Oct 15, 2026
  9. dkackman commented on Oct 15, 2026

    @dkackman
    OwnerAuthor

    Architecture review queued by the loop driver: this hand-off changed dw/ or dw_mcp/ on develop (d0fb3f4596..2ce7f2ab27: dw/plan.py dw/variables.py dw/vram_inheritance.py). The reviewer checks it against docs/ARCHITECTURE.md before the tester verifies.

  10. dkackman commented on Oct 15, 2026

    @dkackman
    OwnerAuthor

    Architecture review: pass (d0fb3f4..2ce7f2a; #908's commit is e243ec7, which touches dw/plan.py, dw/variables.py, dw/vram_inheritance.py and tests/test_inherited_cost.py). claude-opus-5-5 / anthropic, reviewer. I checked it against docs/ARCHITECTURE.md and stage C guardrails item 3.

    What I read

    No finding

    • Second owner: none. The change creates one owner for integral-float canonicalization, which the fingerprint and the inherited comparison now share, instead of a copy in vram_inheritance.py. I grepped dw/ for other is_integer() canonicalizers. variable_constraints.py:134, variables.py:376 and task_domains.py check integrality for validation and don't respell values, so they aren't the same rule.
    • Build vs. buy: nothing in pyproject.toml applies.
    • Map: no row names the helper. The Bound acknowledgement row (ARCHITECTURE.md:97) names dw/plan.py: fingerprint, which still owns the fingerprint and still lives there. The Inherited cost row (:106) still describes differs correctly: by-value comparison doesn't change what is listed. No rule moved owners: a shared utility moved, so no row needs editing.
    • Context: no CLAUDE.md touched. The rationale sits in the same_number docstring and a comment in _carried.

    Waived: none (not arch-approved).

  11. dkackman commented on Oct 15, 2026

    @dkackman
    OwnerAuthor

    Verified: stage C passes. The issue's repro and both pending cases (C-F484, C-F485) pass in one session against develop @ 2ce7f2a, workspace default. claude-opus-5-5 / anthropic, tester

    Setup

    W is get_workflow("templates/minimax/reference-to-video") with these changes:

    • seed: 42;
    • a one-line prompt;
    • observed, cost, summary, vram_estimate and variable_constraints dropped.

    lora_scale: 1.0 and lora_alpha: null are kept. Every call is a validate_workflow, and each variant passes only the named arguments.

    C-F484: pass

    1. W inline: basis: "inherited", inherited_from: "templates/minimax/reference-to-video", 7.8 min (M0), runs 33, differs: [], no scaled.
    2. W with {num_inference_steps: 30, width: 1344, height: 768}: basis: "inherited", 51.1 min, scaled: "scaled from templates/minimax/reference-to-video: steps 30 vs 9; canvas 1344x768 vs 960x544".
      • Expected M0×(30/9)×1.9765 ≈ 51.4, so this is inside ±5%.
    3. By name, {seed: 42, num_inference_steps: 30, width: 1344, height: 768}: basis: "derived", T = 51.9 min, scaled from the curated 7.9.
      • Inline and template paths differ by 1.5%, inside the 10% bound.
    4. W with {num_frames: 192}: basis: "inherited", 12.0 min, scaled: "...frames 192 vs 124", differs: ["frame count"], low_confidence: true.
      • Expected 7.8×192/124 ≈ 12.08.

    C-F485: pass

    1. W as is: differs: [] and no low_confidence. This was the call that bounced twice; the number-spelling fix holds over the real MCP path.
    2. attention_backend: "native": basis: "inherited", 7.1 min, low_confidence: true, differs: ["attention backend"].
      • It now inherits from templates/minimax/voice-timbre-reference (3 runs), not reference-to-video. The case doesn't forbid that, so it isn't a finding.
    3. cache: {type: "first_block", threshold: 0.05}: basis: "inherited", 7.8 min, low_confidence: true, differs: ["cache"].
    4. lora_model_name: null, lora_weight_name: null: basis: "inherited", 7.8 min, low_confidence: true, differs: ["LoRA"].

    Observation (not a finding against any case)

    • C-F484 call 2 returns low_confidence: true with differs: [].
    • Call 4 flags its frame difference in differs as well as scaled. Call 2's steps and canvas scaling sets the flag without naming anything in differs.
    • If low_confidence is meant to come with a reason in differs, this is a small inconsistency. I'm leaving it to the lead to decide whether it matters.

    Suite

    I removed the pending: #908 line from C-F484 and C-F485 in regression-suite-complete.md, so they are now ordinary cases.

  12. added
    status:verifiedTester confirmed the fix via a real MCP call
    and removed on Oct 15, 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

    featureWork bigger than a fix: designed with Don, built in stages (harnest R11)owner:testerTester's turn to actstageA child issue: one stage of a featurestatus:verifiedTester confirmed the fix via a real MCP calltarget:lem

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions