GTR097 — UpgradeToValid: the minimal-bump orchestrator
Contract: declares the minimum vendored profile at or above the tool’s baseline that it validates at; structural-only by composition; never lowers a profile.
The transform
Given a floor (the tool’s declared profile=, or Galaxy’s 16.01 legacy
default when undeclared):
Probe
oldest_valid_profile(document, floor=floor)— the oldest vendored profile at or above the floor the (already-repaired) tool validates at as-is. If found, declare exactly it via GTR007 (UpdateProfile(ceiling=needed)) and stop.Otherwise step through the registered single-step
upgrade_vNcodemods (GTR008, GTR093, GTR009, GTR010, GTR011) for the sticking version, re-probing after each advancing step, and declare the first profile at or above the floor a step unblocks — the declaration lands once, at the minimum.A stall (a sticking version with no registered upgrade, or a step that cannot advance the tool) reverts any structural steps it tried (a snapshot restore) and leaves the tool byte-untouched, reporting the floor via
unreachable_floor(the caller fails the tool closed).
Proof
Every constituent step is individually proven on its own document (GTR012 sequences the same set); this orchestrator adds only validity-gated sequencing toward a minimum, not a maximum:
Never lowers a profile.
oldest_valid_profileonly considers profiles at or above the floor, and the floor is the tool’s own baseline, so the declared profile after the transform is always>= baseline. The bump-up-onlyUpdateProfilereinforces this: it never rewrites a declaration to an older version.Lands at the minimum. Step 1 returns the oldest validating profile at or above the floor, so when the tool validates as-is no structural change runs and
profile=rises no further than required (it is a byte no-op when the tool already validates at its declared baseline). In the stepped path the declaration is deferred until a profile at or above the floor validates, so no intermediate profile is ever declared.Structural-only. The only mutations are the proven
upgrade_vNsteps and the profile declaration; no<command>, Cheetah, or runtime construct is touched, so behaviour at the declared profile is the behaviour the steps already preserve.Terminates. The stepped loop advances only when
newest_valid_profilestrictly improves and halts on a repeat (theseenguard) over the finite vendored profile set.
This is the engine of the shipped default upgrade (codemod
docs/decisions.md §50, registry D22): profile= moves only when the tool is
invalid where it sits, running this after repair instead of walking to the
behaviour ceiling (the opt-in --modernize path keeps using
GTR012). The facade short-circuits before this orchestrator in
the kept and undeclared cases, so it runs only when a bump is actually needed.
See codemod docs/decisions.md §49 for the mechanism decision.