pushdownFilters
Returns a Draft where all DraftStage.Filter (and DraftStage.FusedFilter) nodes in the Free section precede all DraftStage.Map (and DraftStage.FusedMap) nodes.
Branch-aware: applied per weakly-connected component. Each independent branch from a G2 Draft.combine is reordered independently; the two branches are never merged.
Graph-local criterion: the Free section is the sub-path between the Source node and the Embroider node (both excluded). Within this section, a filter node whose predecessor is a map node can be pushed earlier (predecessor-local swap). On a path, pushing all filters before all maps in one pass is equivalent to repeatedly applying the predecessor-local swap.
Why it's safe: filter and map are both CoordinationKind.Free — they are monotone functions. Per the CALM theorem, adjacent monotone stages commute: filter(map(x)) and map(filter(x)) produce the same convergent result. Moving filters earlier reduces the volume of data flowing into map stages.
Modelled assumption — filter independence: this rewrite moves a filter before a map without checking whether the filter's predicate depends on the map's output. Stages carry only symbolic OpIds. The contract is that a DraftStage.Filter's predicate operates on the source element. A future metadata layer could verify independence before reordering.