GTR008 — Upgrade19_01: synthesize required output names (19.01 → 19.05)

Contract: structural-only, with one documented identity-synthesis caveat.

The delta

19.05 makes name required on output <data>; 19.01 admitted a bare <data from_work_dir="…"/>.

The transform

Synthesize a deterministic, collision-free name (output, output2, …) on every unnamed direct <outputs> child, avoiding the shared output-identifier namespace (existing <data> and <collection> names).

Proof

  • In-tool references cannot exist: the output had no name, so no Cheetah $name, <test> output reference, or format_source can point at it — the synthesized name is an unreferenced placeholder identity inside the tool.

  • Collision-freedom is checked against the whole output namespace.

Scope boundary / caveat

  • A <data> nested inside an output <collection> is left on construction grounds (re-verified 2026-06-10): Galaxy asserts the name at parse (tool_util/parser/xml.py:540-541assert output_name), so a nameless one never loaded (no behaviour to preserve), and the name keys output_collection.outputs — user-visible element identity, not an internal placeholder.

  • External surfaces (a workflow referencing the tool’s runtime output identity) are outside the static proof — this is precisely why the rule is an opt-in upgrade step, not a format rule: identity synthesis is part of the upgrade’s semantic contract, surfaced via behavior_preserving.

History

Codemod §14; grown from the discovery sweep; per-rule corpus isolation clean.