# 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): 1. 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](GTR007.md) (`UpdateProfile(ceiling=needed)`) and stop. 2. Otherwise step through the registered single-step `upgrade_vN` codemods ([GTR008](GTR008.md), [GTR093](GTR093.md), [GTR009](GTR009.md), [GTR010](GTR010.md), [GTR011](GTR011.md)) 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. 3. 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](GTR012.md) sequences the same set); this orchestrator adds only **validity-gated sequencing toward a minimum, not a maximum**: - **Never lowers a profile.** `oldest_valid_profile` only 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-only `UpdateProfile` reinforces 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_vN` steps and the profile declaration; no ``, 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_profile` strictly improves and halts on a repeat (the `seen` guard) 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](GTR012.md)). 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.