Skip to content

execution_graph: invalidate readers on host writes#85

Merged
waywardmonkeys merged 1 commit into
forest-rs:mainfrom
waywardmonkeys:execution_graph/host-write-invalidation
May 31, 2026
Merged

execution_graph: invalidate readers on host writes#85
waywardmonkeys merged 1 commit into
forest-rs:mainfrom
waywardmonkeys:execution_graph/host-write-invalidation

Conversation

@waywardmonkeys
Copy link
Copy Markdown
Contributor

Treat host write access events as dirty marks so graph runs that previously read the same resource key are scheduled after a writer mutates that key.

Keep write events in access logs, handle the deps-only fast path the same way, and add a regression covering a writer node invalidating a prior host-state reader. Clarify the host access docs that reads and writes must share the same resource key namespace to interact.

Treat host write access events as dirty marks so graph runs that previously read the same resource key are scheduled after a writer mutates that key.

Keep write events in access logs, handle the deps-only fast path the same way, and add a regression covering a writer node invalidating a prior host-state reader. Clarify the host access docs that reads and writes must share the same resource key namespace to interact.
@waywardmonkeys waywardmonkeys merged commit ddfc71e into forest-rs:main May 31, 2026
15 checks passed
@waywardmonkeys waywardmonkeys deleted the execution_graph/host-write-invalidation branch May 31, 2026 11:13
no-materials added a commit that referenced this pull request Jun 1, 2026
* execution_graph: stop a node's own writes from re-triggering it

  #85 made host writes mark the written key dirty so prior readers are
  invalidated. But a node that both reads and writes the same key then
  invalidated *itself*: the read made its output depend on the key, the
  write re-dirtied it, and the node re-ran on every run_all() forever
  (observed run_count 1, 2, 3, ... with no external change).

  Track the keys a node writes during a run and exclude them from its own
  dependency set (reads ∖ writes). The write still marks the key dirty, so
  other nodes that read it are still invalidated; only the writer's
  self-trigger is removed, so a read-modify-write node now reaches a
  fixpoint.

  Also ignore host writes to graph-owned Input keys: they intern to the
  same id as a node's input binding, so honoring them would let the
  self-write filter strip a real graph-input dependency and leave the node
  stale after invalidate_input. Hosts only own the HostState/OpaqueHost
  namespaces.

  Adds regression tests for both cases.

* fmt & typos

* execution_graph: don't let ignored Input writes satisfy strict-deps

  Host writes to graph-owned Input keys are ignored (mark_tape_key_dirty
  returns None), but the access sinks still bumped the strict-deps counter
  before that rejection. As a result a host call whose only action was
  ctx.record_write(ResourceKeyRef::Input(..)) advanced the counter and
  passed strict-deps, even though the graph recorded no dependency, no
  invalidation, and no access-log entry — weakening the mode's guarantee
  that every host call reports something usable.

  Move the counter increment inside the accepted-write branch in both
  CollectingAccessSink::write and DepsOnlyAccessSink::write, so only
  accepted (HostState/OpaqueHost) writes count as access events. Reads are
  unchanged; non-strict mode still silently ignores Input writes (it never
  reads the counter), while strict mode now rejects a call whose only event
  is an ignored write.

  Adds a regression test asserting StrictDepsViolation for a host call that
  only writes an Input key.
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.

1 participant