Issues planemo reports that we fix

planemo lint (via galaxy.tool_util.linters) is report-only. It tells an author a tool has a problem, but the author fixes it by hand. This project’s differentiator is auto-fixing the subset where a fix is provably safe. This page shows a real before/after for each such fix, paired with the planemo linter it covers and how many corpus tools it touches.

Scope & honesty. The candidate list comes from docs/planemo_linter_parity.md (the full 146-linter map). Each row’s “can we safely fix it?” is decided per-rule when it’s built, the same behaviour-preservation discipline as everywhere else (soundness.md). Sometimes the homework says no and we keep it advisory instead of fixing, that outcome is recorded here too, because declining to change a tool’s identity is itself the right answer.

Status legend: ✅ Shipped (runs under format today) · 🔭 Planned (a FIX candidate not yet built) · 🛑 Advisory-by-design (planemo flags it; we detect but deliberately don’t auto-fix: doing so wouldn’t be behaviour-preserving).


✅ GTR035.1: leading/trailing whitespace in a requirement version

Covers planemo: RequirementVersionWhitespace (galaxy.tool_util.linters.general). Its sibling ToolNameWhitespace is the GTR035.2 advisory (reported under --ruleset strict, never auto-fixed: the name trim is a display-contract change, byte-visible in API JSON; the GTR035 partition, codemod §33 addendum / check D33).

A conda <requirement> version accidentally padded with whitespace. planemo warns “…is pre/suffixed by whitespace, this may cause errors”; we trim it under format.

Before:

<tool id="demo" name="My Demo Tool" version="1.0">
    <requirements>
        <requirement type="package" version=" 1.20 ">samtools</requirement>
    </requirements>

After galaxy-tool-refactor format:

<tool id="demo" name="My Demo Tool" version="1.0">
    <requirements>
        <requirement type="package" version="1.20">samtools</requirement>
    </requirements>

Why it’s safe: Galaxy composes the conda spec verbatim (package_specifier = f"{package}={version}", conda_util.py:461-465), so a whitespace-bearing version never resolved. A working tool never has one and trimming only ever repairs an already-broken requirement. Corpus: per-rule counts live in docs/corpus_check_stats.md / docs/corpus_rule_stats.md (regenerated with the partition): 0 non-idempotent, 0 post-validate-failed across every sweep.

🛑 id / tool version whitespace: detect, don’t fix

Covers planemo: ToolIDWhitespace, ToolVersionWhitespace.

The same accidental whitespace, but on a <tool>’s id or version. We do not auto-trim these: Galaxy uses both raw as the tool’s identity / version key (tool_util/parser/xml.py parse_id/parse_version don’t strip; Tool.id is the registration key), so trimming would change a working tool’s identity, not behaviour-preserving. This is the honest split of the planemo “whitespace” cluster: two attributes we fix, two we (will) only flag. (Advisory rule: planned.)


✅ GTR036: deprecated <output type="data"><data>

Covers planemo: OutputsOutput (“Avoid the use of ‘output’ and replace by ‘data’ or ‘collection’”).

Before:

<outputs>
    <output type="data" name="out" format="txt"/>
</outputs>

After galaxy-tool-refactor format:

<outputs>
    <data name="out" format="txt"/>
</outputs>

Why it’s safe: Galaxy routes a <outputs> child by tag: an <output type="data"> is parsed by the same code path as a <data> (tool_util/parser/xml.py), so the rename + dropping the redundant type="data" is a no-op for Galaxy. Corpus: 1 tool carries it; GTR036 fixes it, 0 non-idempotent, 0 post-validate-failed (docs/corpus_rule_stats.md).

Left advisory (not auto-fixed): <output type="collection"> (Galaxy remaps collection_type/collection_type_source and fills type_source via unicodify(None) when absent, so a literal rename isn’t provably equivalent), and <output> with no type (an expression output, a different kind). Same soundness discipline as the id/version whitespace split above.

✅ GTR037: drop a redundant name when argument implies it

Covers planemo: InputsNameRedundantArgument.

Before:

<inputs>
    <param argument="--threads" name="threads" type="integer" value="1"/>
</inputs>

After galaxy-tool-refactor format:

<inputs>
    <param argument="--threads" type="integer" value="1"/>
</inputs>

Why it’s safe: Galaxy derives name from argument when absent (_parse_name(None, "--threads") = "--threads".lstrip("-").replace("-","_") = "threads"); we drop name only when it equals that derived value, so Galaxy computes the identical name and every $threads reference still resolves. And param/@name is optional in all 28 vendored XSDs that allow argument, so validity is preserved for every profile, including novel tool XML. Corpus: 343 tools carry it (1,846 findings); GTR037 fixes 332, 0 non-idempotent, 0 post-validate-failed (docs/corpus_rule_stats.md).

🛑 Deprecated <options> / select attributes: detect, don’t fix

Covers planemo: InputsSelectDynamicOptions (deprecated dynamic_options=), InputsSelectOptionsDeprecatedAttr (from_file/from_parameter/transform_lines/ options_filter_attribute).

On inspection these have no mechanical modern equivalent: dynamic_options= holds an arbitrary Python expression, and the deprecated <options> attributes require restructuring (e.g. defining a data table). Migrating them needs author judgment, so (like the id/version whitespace and <output type="collection"> cases above) they stay advisory (planned check-tier rules), reported but not auto-fixed.


How this list grows

The auto-fixable subset of planemo’s linters is now complete: GTR035.1 (whitespace trims), GTR036 (<output type="data"><data>), GTR037 (redundant name). Every other candidate, on inspection, is either identity-changing (id/version whitespace) or has no mechanical modern equivalent (<output type="collection">, deprecated dynamic_options/<options> attrs), so it’s advisory-by-design, not a gap. The next planemo-parity frontier is the ~80 correctness checks (param/validator/conditional/test rules): mostly detect-only for us too, growing the advisory check tier rather than this fixer showcase.