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.pysplits:raw — runtime-significant); case stays (exact comparisons).stdio (G1, with G3+G5 folded in):
rangefalls back to thevalueattribute (aliases,parser/xml.py:1248-1250) ⇒ rename, and avaluebesiderangeis never read ⇒ dropped; an<exit_code>with neither attr or a blank range, and a<regex>withoutmatch=(:1318-1324), are logged and skipped at runtime ⇒ the dead elements are deleted.RangeType’s only consumer isExitCode.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 (100MI≡100Mi), and integral scientific forms (129e6≡129000000) 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.