Skip to content

fix(CachedDag): cache the inputs a call was given - #83

Merged
thorwhalen merged 5 commits into
masterfrom
fix/cached-dag-cache-inputs-34
Sep 22, 2026
Merged

thorwhalen merged 5 commits into
masterfrom
fix/cached-dag-cache-inputs-34

Conversation

@thorwhalen

@thorwhalen thorwhalen commented Sep 22, 2026 •

Copy link
Copy Markdown
Member

Closes #34

CachedDag.__call__ used root inputs only transiently, so c('g', a=1) followed by c('f') failed with a missing a.

Changes (all in meshed/scrap/cached_dag.py):

  • Explicitly given inputs that are var nodes of the dag are persisted in cache after a successful computation. Non-var-node kwargs are not cached.
  • Cached values take precedence over the dag's defaults (ChainMap(cache, defaults)), so a cached y=5 is not shadowed by the default y=2. Before this PR the cache only held non-root outputs, which have no defaults, so this doesn't change previous behaviour.
  • Inputs are validated against the cache once per top-level call (_compute now recurses into itself instead of re-entering __call__). An input is rejected if it is cached with a different value, if cached outputs downstream of it were computed without it, or if it is a non-root node the cache + defaults already determine. Inputs of a single call are not validated against each other (documented).
  • Value comparison is identity-first and never raises, so nan and numpy-like inputs work (for those, only the same object counts as the same value).
  • A failed call rolls back the outputs it computed, so the cache stays consistent with its (uncached) inputs and the call can be retried; the rollback can never mask the original exception.
  • A user-supplied Mapping passed as cache= is now actually used (previously self.cache was never set in that branch -> AttributeError).
  • cached_dag_test had an always-true assert c("f" == 2); fixed to c("f") == 2.
  • New meshed/tests/test_cached_dag.py (21 tests; CI's pytest ignores scrap/, so the fix would otherwise be untested).

Docstring examples still marked +SKIP stay skipped: they fail for a separate reason (the dag built by code_to_dag no longer carries defaults), not related to input caching.

Review: four rounds by an independent refute-review agent; each round's findings (recursion re-running the checks, nan/array-like crashes, inputs pinned by failed calls, poisoned cache via intermediate inputs, rollback masking exceptions, over-broad rejection) were fixed and covered by tests.

Dependents: no module in the fleet imports meshed.scrap.cached_dag (grep over all local repos + GitHub code search over thorwhalen/i2mint/otosense/inoocq). Test suites of the 10 local dependents present on this box (allude, dagapp, dotsci, extrude, front, guided, lookbook, theremin, titbit, uf) give byte-identical results with this branch and with master. meshed's own suite (excluding scrap/examples): 192 passed, 1 pre-existing failure (test_hybrid_dag needs the optional http2py).

🤖 Generated with Claude Code

thorwhalen and others added 5 commits September 22, 2026 17:57
- Persist explicitly given var-node inputs in CachedDag.cache after a successful computation.
- Re-passing an input with its cached value is allowed; a different value raises ValueError.
- Cached values take precedence over the dag's defaults.
- A user-supplied Mapping cache is now actually used (was left unset).
- Fix the always-true assertion in cached_dag_test; add meshed/tests/test_cached_dag.py.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Address review of #83: recurse through _compute (not __call__) so the cache
check and input caching run once per call; compare values without raising
(identity first, then guarded ==); reject inputs that contradict cached
downstream outputs; more tests (multi-level, array-like, nan, arg order,
intermediate inputs).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Second review round of #83: a failed call left its intermediate outputs in the
cache while (deliberately) not caching its inputs, so the retry was rejected by
the downstream-contradiction check. Now the keys a failed call added are
removed, and retries are tested.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ollback

Third review round of #83: an intermediate var node given as an input was never
checked against cached values it would be derived from, which silently poisoned
the cache. It is now rejected. The rollback of a failed call no longer masks the
original exception if the cache doesn't support deletion. Documented that inputs
of a single call are not validated against each other.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…termines

Fourth review round of #83: the upstream check fired whenever any ancestor was
cached; now it only fires when every source of the node is settled by the cache
or the dag's defaults, so giving an intermediate whose other inputs are unknown
still works.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@thorwhalen
thorwhalen merged commit 3226386 into master Sep 22, 2026
6 checks passed
@thorwhalen
thorwhalen deleted the fix/cached-dag-cache-inputs-34 branch September 22, 2026 18:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CachedDag.cache should be populated with inputs that it was called on

1 participant