# How must an instance pin collation to prevent cross-host sort divergence? **Date of Record:** 2026 November 2 **Scope:** Applies to string comparisons and sorts that use locale-dependent collation (ICU default, strcoll, database default) across hosts that may differ in locale, ICU version, or collation table. Does not apply to binary comparison or sorts pinned to a named, versioned collation. ## Core Distinction Two string sorts produce the same order only if they use the same collation identifier *and* the same version of the collation table. Locale name alone is insufficient; ICU and glibc produce different orders for the same locale name across versions, and library upgrades change which table is active. **Invariant.** Order is reproducible across hosts if and only if collation is byte-wise, or the collation identifier is versioned and that version is fixed on every host that sorts the same keys. **Violation.** A search index is sorted on one host with ICU 70 and queried on another with ICU 72. Names that were adjacent become separated by a token that moved between versions. Range queries miss rows; pagination returns inconsistent pages. **Asymmetry.** Each host's sort is correct for its own collation. Only the relationship between two correct sorts is broken, and only for characters whose collation changed between versions. ## What Was Observed **Signature.** Pagination or range scans returning different rows on different replicas. Search results ordered differently across regions. Rows appearing in one host's results and not another's for the same range query. **Trace.** A `BETWEEN 'a' AND 'm'` query relies on collation order. Under one ICU version "æ" sorts after "a"; under another it sorts after "z". A row whose name begins with "æ" is included on one replica and excluded on another. No index is corrupt. **Why monitoring stays green.** Each host reports its own sort as consistent with its own state. Cross-host queries see a union that appears complete. ## Condition of Validity The instance must ensure at least one holds before it relies on a sort being reproducible: 1. **Must use binary collation.** Comparison is byte-wise, so order is a function of encoding only. 2. **Must pin version.** A named, versioned collation is used and its version is fixed across hosts and upgrades. 3. **Must sort at one layer.** Sort happens in a single layer after all data is gathered, so only one collation is in play. Condition 1 is the safest for keys used in equality and range filters. The instance must know which applies before it treats two hosts' sorted results as comparable. ## Decision Boundary - Binary collation on both hosts: identical order. - Versioned pinned collation: identical as long as upgrades are coordinated. - Locale name only, no version: divergence is possible on any library upgrade. - Client-side single-collation sort: identical by construction, at the cost of data movement. ## Operational Effect The defect grows slowly as libraries upgrade on independent schedules, then surfaces all at once when two hosts are compared. Remediation is binary collation for keys used in filters, or version-pinned collation with coordinated upgrades. The trap is to declare a locale like "en_US" and assume it is stable. It is a name that maps to a changing implementation. ```python from dataclasses import dataclass class LocaleSortError(RuntimeError): """Raised when string order is not reproducible across hosts.""" @dataclass(frozen=True) class CollationGate: collation: str # "binary", "versioned", "locale-name" pinned_version: str = "" def verify(self) -> bool: if self.collation == "binary": return True if self.collation == "versioned" and self.pinned_version: return True if self.collation == "locale-name": raise LocaleSortError( "locale-name collation without pinned version: order varies across library upgrades" ) raise LocaleSortError(f"collation {self.collation!r} is not reproducible") def dispatch_collation(gate: CollationGate) -> str: try: gate.verify() except LocaleSortError: return "binary" return gate.collation ```