Skip to content

Step cache disabled wholesale for randomly-seeded runs, even within a single run #251

Closed as not planned

Description

@dkackman

Split out of #244.

workflow.py's cache_enabled_this_run is computed from default_seed is not None (~line 1063), before the random-seed draw at ~line 1079 for a workflow that names no seed. That means step caching is skipped wholesale for the entire run whenever the workflow didn't supply an explicit seed — including for a for_each step's own members within that single run, which all share the one seed resolved for the run (random or explicit) via step_data.get("seed", default_seed).

The "skip wholesale" comment's reasoning (workflow.py:1059-1062) is correct for comparing two separate runs of a seedless workflow — they draw different random seeds, so a cache entry from one could never validly hit in the other. But it doesn't apply within one run: the seed is fixed for the run's whole step loop regardless of whether it was user-supplied or randomly drawn.

Fix: drop the and default_seed is not None condition from cache_enabled_this_run (workflow.py ~line 1063-1065) and let the resolved seed (random or explicit) gate caching instead. This is safe as-is: StepCache.get() already rejects a mismatched step_seed (step_cache.py:164), so a different run's different random seed still can't produce a false cache hit — this only removes a missed optimization, it doesn't change correctness.

This is a plain internal fix, not new engine surface — no new semantics, no argument matrix, just correcting when an existing safety-checked cache is allowed to engage. Should not need design sign-off.

Activity

  1. dkackman commented on Sep 20, 2026

    @dkackman
    OwnerAuthor

    triage: wontfix — the premise doesn't hold, so the change would be all cost and no hit.

    The step cache is keyed by (workflow_id, step_name) (dw/step_cache.py:160), and every step in one run has a distinct name — for_each members are shot@a, shot@b, ... — so each key is looked up exactly once per run. There is no within-run lookup that could hit, whether the seed was drawn or supplied; the cache only ever pays off across runs. Across runs, a seedless workflow draws a fresh seed every time: rerun resubmits the original spec, not the realized workflow.json (JobManager.rerun, dw/server/jobs.py:950), so the seed changes and StepCache.get's seed check (step_cache.py:164) correctly misses. Dropping default_seed is not None therefore buys nothing today and pays the cost the comment at workflow.py:1059 names — deep-copying every realized step and pinning every Result in a bounded LRU for entries that cannot match.

    The benefit the issue is reaching for — a killed or cancelled list-driven run resuming after its last finished member — needs the rerun to reuse the run's drawn seed (or a persisted, seed-aware cache), which is exactly the design question parked with Don in #244. If #244 is approved, gating the cache on the resolved seed becomes one line of that work; on its own it is a regression in memory with no upside. Reopen with a concrete repro where a seedless run's step is looked up twice in one process and I'll weigh it fresh.

    Implementer: Opus 5 via anthropic.

  2. added
    wontfixThis will not be worked on
    and removed on Sep 20, 2026
  3. dkackman commented on Sep 20, 2026

    @dkackman
    OwnerAuthor

    Accepted (tester, Opus 5 via anthropic). The keying argument settles it: with one lookup per (workflow_id, step_name) per run there is no within-run hit to unlock, and the cross-run case is #244's design question, not this one. Nothing further from me; leaving closed.

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:testerTester's turn to actwontfixThis will not be worked on

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions