Skip to content

fix: use ordinal string comparison for deterministic ordering#273

Open
YunchuWang wants to merge 1 commit into
mainfrom
copilot-finds/improve/ordinal-string-comparison
Open

fix: use ordinal string comparison for deterministic ordering#273
YunchuWang wants to merge 1 commit into
mainfrom
copilot-finds/improve/ordinal-string-comparison

Conversation

@YunchuWang

Copy link
Copy Markdown
Member

Summary

Fixes #231

Replace localeCompare() with < / > operators in lockEntities() and
compareVersions() for locale-independent, deterministic ordering that
matches the .NET SDK's StringComparer.Ordinal behavior.

Fixes #231

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 18, 2026 17:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a determinism issue in the Durable Task JS SDK by replacing locale-sensitive string comparisons with locale-independent ordinal comparisons, aligning behavior across platforms/locales (and with .NET’s StringComparer.Ordinal* semantics). This directly addresses issue #231, which highlighted potential non-deterministic ordering in entity lock acquisition and version comparison.

Changes:

  • Updated lockEntities() to sort entity IDs using ordinal string comparison instead of localeCompare(), ensuring deterministic lock ordering.
  • Updated compareVersions() to use ordinal (case-insensitive) ordering for non-semver fallbacks instead of localeCompare().
  • Added/updated unit tests to validate ordinal ordering behavior and prevent regressions.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
packages/durabletask-js/src/worker/runtime-orchestration-context.ts Replaces locale-dependent entity ID sorting with deterministic ordinal comparison for lock ordering.
packages/durabletask-js/src/utils/versioning.util.ts Replaces locale-dependent fallback version comparison with deterministic ordinal (case-insensitive) comparison.
packages/durabletask-js/test/entity-locking.spec.ts Adds a regression test ensuring lockEntities() ordering is deterministic and not locale-dependent.
packages/durabletask-js/test/versioning.spec.ts Updates/adds tests to ensure non-semver version comparisons are deterministic and not locale-dependent.

Comment on lines +866 to +869
// Sort entities for deterministic ordering (prevents deadlocks).
// Use ordinal (code-point) comparison for cross-platform consistency,
// matching .NET's StringComparer.Ordinal. localeCompare() is locale-dependent
// and can produce different orderings on different machines/locales.
expect(lockSet[2]).toBe("@counter@c");
});

it("should sort entities by ordinal (code-point) order, not locale order", async () => {
Comment on lines +154 to +157
// In many locales, localeCompare() sorts accented characters adjacent to their
// base letters (e.g., "ä" near "a"). Ordinal (code-point) comparison places
// them by their Unicode value instead. This ensures consistent cross-platform
// ordering that matches the .NET SDK's StringComparer.Ordinal.
expect(compareVersions("Alpha", "BETA")).toBeLessThan(0);
});

it("should use ordinal (code-point) order, not locale order", () => {
Comment on lines +91 to +93
// In ordinal comparison, uppercase letters (U+0041-U+005A) come before
// lowercase letters (U+0061-U+007A) after lowercasing they are equal.
// But characters outside ASCII can differ between ordinal and locale:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants