Skip to content

v1.4.0

Choose a tag to compare

@NemSothea NemSothea released this 05 Jun 15:53

What's Changed

Bug Fixes & Hardening (code-review findings 5–8)

Finding 5 — Reliable payload size enforcement (BundledJSONDataSource)
Removed the unreliable url.resourceValues(forKeys: [.fileSizeKey]) pre-flight size check, which silently no-ops on sandboxed or virtual filesystems. The post-read data.count guard is now the sole, authoritative enforcement point.

Finding 6 — Query clamp at the correct altitude (AddressSearchEngine, KhmerNormalizer)
Moved the maxQueryLength truncation from the shared KhmerNormalizer utility into AddressSearchEngine.search() — the correct layer (user-query entry point). The normalizer is now a pure text utility with no search-specific concerns; the clamp no longer fires during index building.

Finding 7 — Consistent traversal contract (AddressStore)
districts(inProvince:), communes(inDistrict:), and villages(inCommune:) now throw AddressError.notFound for unknown parent codes instead of silently returning []. Callers can now reliably distinguish "valid empty list" from "unrecognised code" — consistent with selection(forVillageCode:) which has always thrown.

Finding 8 — Shared cache decode path + async file I/O (DatasetCache, DatasetDecoding, CachingDataSource)

  • Added DatasetDecoding.decodeDataset() for the domain-model cache schema (full property names, distinct from the wire format's short keys). DatasetCache.read() now routes through it for consistent AddressError.decodingFailed mapping.
  • Added DatasetCache.readAsync() which offloads blocking file I/O to DispatchQueue.global(qos: .userInitiated). CachingDataSource.bestAvailable(), version, and refresh() all use this path, keeping the Swift cooperative thread pool unblocked.

Tests

  • unknownParentReturnsEmptyunknownParentThrowsNotFound (reflects new throwing contract)
  • Clamp coverage moved from KhmerNormalizerTests to AddressSearchEngineTests.clampsOverlongQuery
  • 138 tests passing, zero warnings under Swift 6 strict concurrency