docs: updated docs with a cross-branch read gotcha

2026-05-20 19:01:01 -06:00
parent c88b5be6da
commit 732d43e298
+50
@@ -902,6 +902,47 @@ This means:
need that pattern, sequentialize the work or write it as a single
multi-step subgraph
### Cross-branch reads are not visible (gotcha)
A consequence of independent state forks: a branch **cannot read a key
that a sibling branch writes in the same super-step**. Each branch
sees the state snapshot taken BEFORE the super-step started; sibling
writes only become visible at the next super-step (after the join).
**Validator catches this at load time.** If any branch's templated
field references a state key that another sibling branch writes in
the same super-step, you get a load-time error like:
```
node 'rag_lookup' reads state key(s) `db_result` which sibling parallel
branch 'query_local_db' writes in the same super-step; parallel
branches see a state snapshot taken BEFORE the super-step and cannot
observe each other's writes. Move the dependent read to a later
super-step (or remove the cross-branch reference).
```
**Fix options:**
- **Remove the dependency.** Drop the cross-branch reference from the
prompt/query/etc. so the branch operates on what was available _before_
the super-step.
- **Sequentialize.** Put the dependent node in a later super-step:
`producer → reader_that_needed_producer_output` instead of
`[producer, reader_that_needed_producer_output]`.
- **Use the join.** Restructure so any node that depends on a sibling's
writes runs _after_ the join. The join sees the merged state.
**Caveat (scripts).** The validator scans templated fields of typed
nodes (`prompt`, `query`, `instructions`, `question`, `default`,
`output`, `over`, and `state_updates` values). It does not scan
script bodies, since scripts read state opaquely via `GRAPH_STATE` /
`GRAPH_STATE_FILE` env vars. A Python script in a parallel branch
that does `state.get("sibling_written_key")` will silently see the
**pre**-super-step snapshot. The script's required `state_updates`
declaration (the validator's separate "parallel scripts must declare
writes" check) covers writes only, not reads. Be aware that script
branches need to be designed so they don't depend on sibling writes.
## Multi-branch UX
In a TTY:
@@ -1182,6 +1223,15 @@ startup.
add explicit declarations
- **`max_concurrency` set to 0**: either `settings.max_concurrency: 0` or
`MapNode.max_concurrency: 0` is rejected (would deadlock the semaphore)
- **Cross-branch read in a parallel super-step**: one branch's templated
field (`prompt`, `query`, `instructions`, `question`, `default`,
`output`, `over`, or `state_updates` value) reads a state key that
another sibling branch writes in the same super-step. Branches see a
snapshot taken _before_ the super-step started, so a sibling's writes
are not yet visible. The error names the reader, the reads-key, and
the sibling writer. Scripts are exempt because their reads are opaque
to static analysis. See [Cross-branch reads are not visible](#cross-branch-reads-are-not-visible-gotcha)
for the script caveat
**Warnings (printed, execution continues)**: