Summary
Align (or explicitly document and gate) the context key-collision rules between linear and DAG flows, which currently differ: linear flows silently overwrite earlier step outputs, while DAG flows reject same-level sibling collisions but allow level-to-level overwrites.
Why this matters
The accumulated execution context is the data plane of every flow. Silent overwrites mean a reordering or added step can drop data with no error and only a DEBUG-level log line — a subtle correctness trap. The asymmetry also means a flow's safety against collisions changes when it is converted between linear and DAG forms.
Current evidence
- Linear merge (
executor.py ~lines 1324–1332): key collisions log at DEBUG and context.update(record.outputs) overwrites.
- DAG merge (
executor.py ~lines 4024–4063): sibling collisions within a level abort the flow with FlowExecutionError, but level_outputs then overwrite prior context keys across levels (~line 4100).
- The asymmetry is noted in code comments (~lines 3716–3717) but not surfaced to users in docs or at compile time.
Proposed implementation
- Choose a uniform policy. Recommended: a flow-level
on_context_collision setting with values "overwrite" (current linear behavior), "error", and "warn"; default "warn" for one minor release, then consider "error" as the default in a later release.
- Implement the policy in one shared merge helper used by both linear and DAG paths (pairs with the sync/async consolidation issue).
- Keep DAG sibling-collision rejection unconditional (it is genuinely ambiguous), and apply the policy to sequential/level-to-level overwrites in both flow kinds.
- Surface predictable collisions statically where possible:
compile_flow() can warn when two steps' output schemas share field names.
- Document the merge semantics in
docs/data-integrity.md and AGENTS.md §5.
Acceptance criteria
- One shared merge implementation governs both flow kinds.
on_context_collision="error" aborts with a typed error naming the step and key; "warn" logs at WARNING; "overwrite" preserves current behavior.
compile_flow emits a warning for statically detectable collisions.
- Documented semantics match implemented behavior.
Test plan
- New tests covering each policy value for linear and DAG flows, plus the compile-time warning.
- Existing execution tests pass with the compatibility default.
- Full validation commands pass.
Migration notes
Default change from silent overwrite to WARNING-level logging is observable but non-breaking. If the default later moves to "error", announce via deprecation notes one minor release ahead per docs/versioning-policy.md.
Risks and tradeoffs
- Some legitimate flows intentionally shadow keys (e.g., refine-in-place pipelines); the
"overwrite" opt-out keeps them working.
- A new
Flow field touches serialization/schema export; update schemas.py and round-trip tests accordingly.
Suggested labels
reliability, breaking-change, architecture
Summary
Align (or explicitly document and gate) the context key-collision rules between linear and DAG flows, which currently differ: linear flows silently overwrite earlier step outputs, while DAG flows reject same-level sibling collisions but allow level-to-level overwrites.
Why this matters
The accumulated execution context is the data plane of every flow. Silent overwrites mean a reordering or added step can drop data with no error and only a DEBUG-level log line — a subtle correctness trap. The asymmetry also means a flow's safety against collisions changes when it is converted between linear and DAG forms.
Current evidence
executor.py~lines 1324–1332): key collisions log at DEBUG andcontext.update(record.outputs)overwrites.executor.py~lines 4024–4063): sibling collisions within a level abort the flow withFlowExecutionError, butlevel_outputsthen overwrite prior context keys across levels (~line 4100).Proposed implementation
on_context_collisionsetting with values"overwrite"(current linear behavior),"error", and"warn"; default"warn"for one minor release, then consider"error"as the default in a later release.compile_flow()can warn when two steps' output schemas share field names.docs/data-integrity.mdand AGENTS.md §5.Acceptance criteria
on_context_collision="error"aborts with a typed error naming the step and key;"warn"logs at WARNING;"overwrite"preserves current behavior.compile_flowemits a warning for statically detectable collisions.Test plan
Migration notes
Default change from silent overwrite to WARNING-level logging is observable but non-breaking. If the default later moves to
"error", announce via deprecation notes one minor release ahead perdocs/versioning-policy.md.Risks and tradeoffs
"overwrite"opt-out keeps them working.Flowfield touches serialization/schema export; updateschemas.pyand round-trip tests accordingly.Suggested labels
reliability, breaking-change, architecture