Why Frozen Version Numbers Break Feature Gates
A common pattern gates functionality on a minimum browser version parsed from the user agent. Frozen and reduced version components turn that comparison into something that no longer means what it did.
The gate is a proxy for a capability
A version threshold is shorthand for a feature that arrived in a particular release. The code wants the feature and tests the version because it is easier to read.
The proxy holds only while the version tracks releases faithfully. It has no independent validity.
Once a component is frozen, the comparison still runs and still returns a value, but it is comparing against a constant.
Different components froze at different times
Platform versions were capped on some systems, minor components fixed on others, and build identifiers flattened separately. There is no single freeze date.
Code parsing several numbers may find one live and the rest constant, which produces results that appear partly sensible.
Nothing distinguishes a frozen component from a live one by inspection, so the failure is invisible in the code.
Gates on platform version fail hardest
Gating on an operating system version to infer support for something is the most affected pattern, because platform version capping is widespread.
All newer systems report the capped value, so the gate treats every current system as if it were at the cap.
Depending on the comparison's direction, that either enables the feature for systems that lack it or disables it for systems that have it.
Capability tests are the direct replacement
Testing whether the feature exists answers the question the gate was asking, correctly, on clients no version table describes.
Most such tests are a single check for an interface, which is less code than parsing and comparing a version.
They also stay correct when a vendor backports a feature or removes one, situations no version comparison handles.
Where a version genuinely matters
Working around a defect in a specific range of releases is the legitimate case, because the feature exists and misbehaves, so testing for it succeeds.
Those workarounds should be narrow and dated in a comment, since they exist for a bug that will be fixed and become dead code.
An accurate version for that purpose is better taken from a structured hint than parsed from a header whose numbers may already be constants.