CollationDelta
Detect string ordering and equality changes before a runtime upgrade.
CollationDelta records a comparator's results for your string corpus, saves a portable capture, and compares captures offline. Capture a baseline in one runtime and the same corpus and requested profile in another. The original runtimes are needed only to create the captures.
It reports equality merges, equality splits, and order reversals as individual pair
witnesses. Equality means compare(a, b) == 0; it does not mean matching bytes or SQL
equality. A runtime version change alone is not drift.
The Python CLI has no runtime dependencies. The included Node and optional native
Chromium adapters implement the same strict intl.collator.v1 contract. Custom
executable adapters can record an application's own comparator.
Install
CollationDelta 0.2 requires Python 3.10+ on Linux or macOS. Node is needed for Node capture; browser capture also requires an explicitly installed Chromium runtime and optional Playwright toolchain. Windows adapter execution is unsupported.
From source
git clone https://github.com/0then0/collationdelta.git
cd collationdelta
uv sync --locked --python 3.10
uv run --locked collationdelta --help
To install a local wheel:
uv build
uv venv /tmp/collationdelta-install --python 3.10
uv pip install --python /tmp/collationdelta-install/bin/python \
dist/collationdelta-0.2.0-py3-none-any.whl
/tmp/collationdelta-install/bin/collationdelta --version
Published releases
pip install collationdelta==0.2.0
collationdelta --version
Version 0.2.0 includes Node capture, optional native browser capture and Python 3.10 support. The older 0.1.0 release requires Python 3.12+ and includes Node capture only.
Capture and compare
Node is required for this example. Run it from the source checkout:
adapter="$(uv run --locked collationdelta node-adapter)"
uv run --locked collationdelta capture \
--corpus examples/corpus.json --profile examples/profile.json \
--output /tmp/baseline.json -- node "$adapter"
uv run --locked collationdelta capture \
--corpus examples/corpus.json --profile examples/profile.json \
--output /tmp/current.json -- node "$adapter"
uv run --locked collationdelta compare /tmp/baseline.json /tmp/current.json \
--json-output /tmp/report.json
Using the same runtime twice gives a control capture. To check an upgrade, run the first capture in the old environment and the second in the new environment. Offline comparison needs only Python and the two capture files.
For native browser capture, see the
browser guide.
collationdelta browser-adapter prints the bundled browser adapter path. Browser
installation and executable selection are explicit; capture never downloads a browser.
Inputs
Corpus JSON assigns a stable ID to each exact string:
{
"version": 1,
"entries": [
{ "id": "rupee", "value": "₨" },
{ "id": "letters", "value": "Rs" },
{ "id": "zero", "value": "0" }
]
}
A requested profile identifies the comparator contract and configuration:
{
"version": 1,
"contract": "intl.collator.v1",
"locale": "en",
"options": { "sensitivity": "base" }
}
IDs must be unique and nonempty. Duplicate values under different IDs are allowed. Strings are preserved exactly: no trimming, case folding, normalization, or removal of controls. Empty strings, U+0000, newlines, combining marks and supplementary characters are supported. Invalid UTF-8 and unpaired surrogates are rejected.
Each capture requests all n² ordered comparisons, including the diagonal, for 1–256 entries. There is no sampling. JSON files are limited to 32 MiB; long strings can reach file or transport limits before the entry limit.
The reference adapters fix localeMatcher to lookup. They support sensitivity,
numeric, caseFirst, ignorePunctuation, usage, and collation. Locale
canonicalization and supported lookup negotiation are allowed. Explicit options and
recognized co, kn, kf extensions must resolve, with explicit options taking
precedence. An unsupported locale or ignored explicit request returns unsupported,
a reason, any known resolved settings, and no comparisons.
See the protocol specification for option values, schemas and custom adapters.
Results and exit codes
Human reports show status, coverage and pair witnesses with IDs, escaped original
strings, Unicode code points and old/new signs. Findings appear once per unordered
pair. --limit N limits displayed findings only; full JSON evidence remains available.
compare --format json prints a deterministic report, and --json-output FILE saves it.
- 0: complete
CAPTUREDorSTABLE; informational commands. - 1: complete
DRIFTwith one or more findings. - 2:
INCOMPLETEorDRIFT_INCOMPLETE. Valid partial or unsupported capture evidence is saved with this code. - 3:
ERROR: invalid or incompatible inputs, corrupt digests, contradictory relations, malformed protocol, launch/crash/timeout or output-limit failure. Capture leaves an existing destination untouched.
Unknown comparisons are never treated as equality. Incomplete evidence can retain a
finding when either direction of the pair was successfully observed on each side;
this does not increase completed coverage or justify STABLE.
Saved runtime examples
The Node upgrade case
compares official Node 18.20.8 and 24.21.0 binaries. It records an equality merge for
₨ / Rs and an order reversal for ₨ / 0, with repeated captures and offline
reports. An unchanged sorted snapshot hides the equality change; a small deduplication
example shows its application consequence.
The Node/browser case
uses eight Icelandic names, Node 24.21.0 and Google Chrome for Testing 156.0.8078.4 on
macOS arm64. Both support en and return STABLE on this corpus. Node supports is;
this browser reports no supported lookup match and known resolved locale en-US.
Strict offline comparison returns INCOMPLETE, zero findings. Fallback relations are
not substituted for missing strict observations.
These are finite comparison experiments, not production incidents or evidence about every browser distribution. Newer builds may legitimately change locale support.
Evidence and guarantees
Captures embed the original corpus, requested profile, effective settings, runtime and adapter metadata, relation signs, explicit failures, coverage, invocation details, limits, diagnostics and a SHA-256 digest. Loading revalidates the digest, schema, coverage and finite-order consistency.
Compatible captures must have identical ID/value mappings and requested profiles, including locale spelling. Entry order may differ. Effective settings may differ and are reported for interpretation. Validation rejects nonzero self comparisons, nonzero comparisons of identical strings, contradictory reciprocals/equality and strict-order cycles. Partial validation checks only known constraints.
Transport bounds time and stdout/stderr output. The POSIX supervisor terminates the adapter process group on completion and failure. Capture files are written through a temporary file and atomically replaced after validation and serialization succeed.
A digest detects content alteration; it is not a signature or runtime authentication. Version labels and user agents are observations or adapter claims. Preserve executable provenance separately when it matters. Captures may include sensitive strings and argv.
Scope
Stability on a finite corpus says nothing about all Unicode strings. Drift means a
change from the selected baseline, not a specification violation. CollationDelta does
not implement UCA, supply locale data, repair sorting, validate database indexes, or
establish SQL UNIQUE/GROUP BY behavior.
Unicode Conformance tests against Unicode/CLDR specifications. CollationDelta uses your saved comparator baseline. glibc-unicode-sorting studies sorting changes through PostgreSQL over large datasets. CollationDelta uses a bounded user corpus and explicit equality/order witnesses.
Development
uv sync --locked --python 3.10
uv run --locked ruff check .
uv run --locked ruff format --check .
uv run --locked pytest
uv build
See testing and environments for browser integration, supported-runtime coverage and packaging checks. See the changelog and release guide for release maintenance. The project uses the Apache-2.0 license.
Metadata
Release files for collationdelta 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| collationdelta-0.2.0.tar.gz | 89.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| collationdelta-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 115.0 kB
Release files / collationdelta-0.2.0.tar.gz
| Download URL | collationdelta-0.2.0.tar.gz |
|---|---|
| Size | 89.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6f850774ea9a314ecda7804d2ea0560fff020228e32b0321320e2ad34b7cf2a2
|
|
BLAKE2b-256 checksum How to use checksums |
e9d28f692bf4f90cc5f497f7ebad3120728aa1c8bc665c0affb6dcd2f56acfce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency logRelease files / collationdelta-0.2.0-py3-none-any.whl
| Download URL | collationdelta-0.2.0-py3-none-any.whl |
|---|---|
| Size | 25.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bcb4b5155929ef5e43b59e9a410b57121cfe8af947537a8d27ce326cffdafaed
|
|
BLAKE2b-256 checksum How to use checksums |
260ea496540d8896765cdb3f625f01774dcb086380eedbd644406032dc09cb09
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency log