Skip to content

Replace remaining localeCompare sorts on determinism-contract surfaces #115

Description

@mbeacom

Raised by @davesheffer on #106 and partly fixed there. This covers the remainder.

Why it matters

localeCompare depends on the runtime's ICU locale, so two environments order the same string set differently:

localeCompare : [src/a_b.ts, src/a-b.ts, src/a.ts, src/A.ts, src/ab.ts, src/aB.ts]
code-unit     : [src/A.ts, src/a-b.ts, src/a.ts, src/aB.ts, src/a_b.ts, src/ab.ts]

#106 fixed the two load-bearing instances — markers/read.ts, which decides which files survive the 3,000-path cap, and the markerScan path lists, whose skippedPaths order feeds cappedScanFinding's slice(0, 10). Both now use compareCodeUnits from packages/core/src/ordering/, which already existed.

The remaining sites are not merely display order. CheckOutcome documents itself as:

Deterministic and pure: identical (lint, changedFiles, snapshots, markerScans) produces identical output.

These arrays serialize into adr check --json, which @adrkit/ci consumes. Under a different ICU locale, identical inputs produce different output bytes. The set membership is fixed; the contract is about the bytes.

Known sites

  • packages/core/src/check/index.tsuniqueSorted, applied to changedFiles. Pre-dates feat(core,ci): wire inbound @adr markers into check #106.
  • packages/core/src/markers/resolve.tscompareDeclarations and the recordId sort.
  • packages/ci/src/changed-files.ts — the changedFiles / markerFiles sorts and the changed-dependency sort.

Worth a sweep rather than a spot fix, since compareCodeUnits already exists and the anomaly was reaching for localeCompare at all.

Worth considering alongside

A lint rule or test that fails on a new localeCompare in any path that reaches serialized output. Otherwise the next one lands the same way this batch did.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions