f92065bc0b
Guards for the three cross-field invariants (source timeout vs lease TTL, stall window vs max TTFT, probe TTL vs slowest timeout) only ran inside from_env, so the from_settings path could build a GatewaySettings that violates the class's own documented invariants. Design moves all of them plus a non-empty sources check into __post_init__ as _validate_* methods, matching the existing frozen dataclasses in types.py. Covers two defects left by PR#1: probe_ttl_s was never moved, and an empty sources tuple leaked a bare 'max() arg is an empty sequence'.