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, orformat_sourcecan 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-541—assert output_name), so a nameless one never loaded (no behaviour to preserve), and the name keysoutput_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
upgradestep, not aformatrule: identity synthesis is part of the upgrade’s semantic contract, surfaced viabehavior_preserving.
History
Codemod §14; grown from the discovery sweep; per-rule corpus isolation clean.