GTR093 — Upgrade21_09 — collection_type / stdio / has_size (upgrade step)

Contract: behaviour-preserving (runtime no-ops).

Claim

Each 21.09→22.01 repair is a runtime no-op that restores 22.01 validity.

The stdio and Bytes slices are the G-series gap-audit items (G1+G3+G5 and G2 respectively, ../deferred_fix_opportunities.md); G4 — the only G-series decline — is recorded there, not here (no fixable rule shipped: nameless groups were runtime-broken, so no behaviour exists to preserve).

Proof, per slice

  • collection_type comma-token strip (ledger item A1): Galaxy’s runtime strips each comma token itself (DataCollectionToolParameter.__init__: [t.strip() for t in collection_types.split(",")], parameters/basic.py:2717, unconditional). "" drops (falsy — identical to absent); whitespace-only stays (a matches-nothing restriction — lifting it would change behaviour); colon-inner whitespace stays (type_description.py splits : raw — runtime-significant); case stays (exact comparisons).

  • stdio (G1, with G3+G5 folded in): range falls back to the value attribute (aliases, parser/xml.py:1248-1250) ⇒ rename, and a value beside range is never read ⇒ dropped; an <exit_code> with neither attr or a blank range, and a <regex> without match= (:1318-1324), are logged and skipped at runtime ⇒ the dead elements are deleted. RangeType’s only consumer is ExitCode.range, and the runtime range parser strips all whitespace.

  • has_size Bytes (G2): the runtime parser is galaxy.util.bytesize.parse_bytesize (upper() + suffix-table strip + int()/float()): whitespace forms, wrong-case suffixes (100MI100Mi), and integral scientific forms (129e6129000000) canonicalize provably; plain-B/word-suffix forms ("2 TB") are NOT in the suffix table — never runtime-working, left alone; non-integral parses left.

History

Codemod §41 (collection_type, reversing a one-tool corpus decline) + §42 (the G-series stdio + Bytes additions). 0 corpus incidence for the stdio/Bytes shapes — novel-tool insurance.