GTR009 — Upgrade24_0: hoist identical element filters (24.0 → 24.1)

Contract: behaviour-preserving restructure (equivalence by Galaxy’s filter semantics).

The delta

24.1 forbids <filter> inside a collection’s child <data> (only actions/change_format remain); top-level output <data> filters stay legal.

The transform

When every child <data> of a collection carries the same <filter> condition, hoist one copy to the <collection> and drop the per-element ones.

Proof

A filter is a Python condition deciding whether the output appears. Identical conditions on all elements ⇔ one condition on the whole collection: in both forms the collection’s elements exist exactly when the condition holds. Galaxy evaluates filter texteval(filter.text.strip()) — which also settles the 2026-06-04 adversarial claim: a post-comment tail inside <filter> is dead at runtime, so the hoist dropping it changes nothing (refutation overreach, re-verified, PR #115).

Scope boundary (bails, reported by the discovery sweep)

  • differing child filters (genuine per-element selection);

  • partially-filtered collections (hoisting would newly filter the rest);

  • a collection already carrying its own filter (hoisting would AND a second condition).

History

Codemod §14; the refutation-overreach record lives in the ledger.