Skip to content

Tags: pinterest/PINCache

Tags

releases/p14.40

Toggle releases/p14.40's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fix crashes and unbounded memory in disk cache trimming (#336)

* Fix crashes and unbounded memory in disk cache trimming

trimToSize:, trimToSizeByEvictionStrategy:, and trimToDate: sorted the
entire metadata dictionary with keysSortedByValueUsingComparator:, which
materializes O(N) temporary storage inside CoreFoundation. On large
caches under memory pressure that allocation fails and traps in
__CFCreateArrayStorage — and since every subsequent trim hits the same
wall, a cache that grows too big to sort can never shrink again.

- Select eviction candidates in bounded 256-key batches (single pass,
  binary-search insertion, O(batch) memory) and loop until under the
  byte target, so trims always make progress. An attempted-keys set
  guarantees termination when eviction declines ghost entries.
- trimToDate: is a pure threshold filter; drop its sort entirely.
- Nil-safe comparators: metadata dates/size are nil when
  resourceValuesForKeys: fails during the initial disk scan.
  [NSNumber compare:nil] RAISES NSInvalidArgumentException (a real crash
  in trimToSize:), and [NSDate compare:nil] returns NSOrderedSame, which
  made the sorts weakly inconsistent. Unknown-metadata entries now sort
  first and are evicted before entries with known access times.
- Guard NSUInteger underflow in the trim loops: stale metadata sizes
  overshooting byteCount made the break condition unsatisfiable and
  evicted the entire cache.

Adds a multi-batch trim regression test (300 entries > one batch).

* Fix CI for current macos-latest runner image (macOS 26)

CI was failing at the first xcrun/xcodebuild invocation with
"xcrun: error: missing DEVELOPER_DIR path: /Applications/Xcode_15.2.app".
Root cause: GitHub's macos-latest label now resolves to the macOS 26
runner image, which only ships Xcode 26.x — the pinned Xcode 15.2 (and
several other things the build relied on) no longer exist on the image.

Changes, following TextureGroup/Texture's CI setup:

- DEVELOPER_DIR now points at Xcode_26.5.0.app (the image default;
  see the runner-images manifest linked in the workflow comment).
- Makefile simulator destination bumped from "iPhone 15" to
  "iPhone 17", since the iPhone 15 simulator does not exist under
  Xcode 26 on the image.
- xcpretty replaced with xcbeautify: the runner images stopped
  preinstalling the xcpretty gem (macOS 26 ships only xcbeautify
  3.2.1), so the "xcodebuild | xcpretty" pipes would fail with
  command-not-found. Error propagation is unchanged — the Makefile's
  "SHELL=/bin/bash -o pipefail" still surfaces xcodebuild failures
  through the pipe.
- Removed the platform matrix from the test job; nothing ever
  referenced matrix.platform (the Makefile owns the destination).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Dan Reed <dreed@pinterest.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

releases/p14.39

Toggle releases/p14.39's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fix crashes and unbounded memory in disk cache trimming (#336)

* Fix crashes and unbounded memory in disk cache trimming

trimToSize:, trimToSizeByEvictionStrategy:, and trimToDate: sorted the
entire metadata dictionary with keysSortedByValueUsingComparator:, which
materializes O(N) temporary storage inside CoreFoundation. On large
caches under memory pressure that allocation fails and traps in
__CFCreateArrayStorage — and since every subsequent trim hits the same
wall, a cache that grows too big to sort can never shrink again.

- Select eviction candidates in bounded 256-key batches (single pass,
  binary-search insertion, O(batch) memory) and loop until under the
  byte target, so trims always make progress. An attempted-keys set
  guarantees termination when eviction declines ghost entries.
- trimToDate: is a pure threshold filter; drop its sort entirely.
- Nil-safe comparators: metadata dates/size are nil when
  resourceValuesForKeys: fails during the initial disk scan.
  [NSNumber compare:nil] RAISES NSInvalidArgumentException (a real crash
  in trimToSize:), and [NSDate compare:nil] returns NSOrderedSame, which
  made the sorts weakly inconsistent. Unknown-metadata entries now sort
  first and are evicted before entries with known access times.
- Guard NSUInteger underflow in the trim loops: stale metadata sizes
  overshooting byteCount made the break condition unsatisfiable and
  evicted the entire cache.

Adds a multi-batch trim regression test (300 entries > one batch).

* Fix CI for current macos-latest runner image (macOS 26)

CI was failing at the first xcrun/xcodebuild invocation with
"xcrun: error: missing DEVELOPER_DIR path: /Applications/Xcode_15.2.app".
Root cause: GitHub's macos-latest label now resolves to the macOS 26
runner image, which only ships Xcode 26.x — the pinned Xcode 15.2 (and
several other things the build relied on) no longer exist on the image.

Changes, following TextureGroup/Texture's CI setup:

- DEVELOPER_DIR now points at Xcode_26.5.0.app (the image default;
  see the runner-images manifest linked in the workflow comment).
- Makefile simulator destination bumped from "iPhone 15" to
  "iPhone 17", since the iPhone 15 simulator does not exist under
  Xcode 26 on the image.
- xcpretty replaced with xcbeautify: the runner images stopped
  preinstalling the xcpretty gem (macOS 26 ships only xcbeautify
  3.2.1), so the "xcodebuild | xcpretty" pipes would fail with
  command-not-found. Error propagation is unchanged — the Makefile's
  "SHELL=/bin/bash -o pipefail" still surfaces xcodebuild failures
  through the pipe.
- Removed the platform matrix from the test job; nothing ever
  referenced matrix.platform (the Makefile owns the destination).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Dan Reed <dreed@pinterest.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

releases/p14.38

Toggle releases/p14.38's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fix crashes and unbounded memory in disk cache trimming (#336)

* Fix crashes and unbounded memory in disk cache trimming

trimToSize:, trimToSizeByEvictionStrategy:, and trimToDate: sorted the
entire metadata dictionary with keysSortedByValueUsingComparator:, which
materializes O(N) temporary storage inside CoreFoundation. On large
caches under memory pressure that allocation fails and traps in
__CFCreateArrayStorage — and since every subsequent trim hits the same
wall, a cache that grows too big to sort can never shrink again.

- Select eviction candidates in bounded 256-key batches (single pass,
  binary-search insertion, O(batch) memory) and loop until under the
  byte target, so trims always make progress. An attempted-keys set
  guarantees termination when eviction declines ghost entries.
- trimToDate: is a pure threshold filter; drop its sort entirely.
- Nil-safe comparators: metadata dates/size are nil when
  resourceValuesForKeys: fails during the initial disk scan.
  [NSNumber compare:nil] RAISES NSInvalidArgumentException (a real crash
  in trimToSize:), and [NSDate compare:nil] returns NSOrderedSame, which
  made the sorts weakly inconsistent. Unknown-metadata entries now sort
  first and are evicted before entries with known access times.
- Guard NSUInteger underflow in the trim loops: stale metadata sizes
  overshooting byteCount made the break condition unsatisfiable and
  evicted the entire cache.

Adds a multi-batch trim regression test (300 entries > one batch).

* Fix CI for current macos-latest runner image (macOS 26)

CI was failing at the first xcrun/xcodebuild invocation with
"xcrun: error: missing DEVELOPER_DIR path: /Applications/Xcode_15.2.app".
Root cause: GitHub's macos-latest label now resolves to the macOS 26
runner image, which only ships Xcode 26.x — the pinned Xcode 15.2 (and
several other things the build relied on) no longer exist on the image.

Changes, following TextureGroup/Texture's CI setup:

- DEVELOPER_DIR now points at Xcode_26.5.0.app (the image default;
  see the runner-images manifest linked in the workflow comment).
- Makefile simulator destination bumped from "iPhone 15" to
  "iPhone 17", since the iPhone 15 simulator does not exist under
  Xcode 26 on the image.
- xcpretty replaced with xcbeautify: the runner images stopped
  preinstalling the xcpretty gem (macOS 26 ships only xcbeautify
  3.2.1), so the "xcodebuild | xcpretty" pipes would fail with
  command-not-found. Error propagation is unchanged — the Makefile's
  "SHELL=/bin/bash -o pipefail" still surfaces xcodebuild failures
  through the pipe.
- Removed the platform matrix from the test job; nothing ever
  referenced matrix.platform (the Makefile owns the destination).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Dan Reed <dreed@pinterest.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

releases/p14.37

Toggle releases/p14.37's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fix crashes and unbounded memory in disk cache trimming (#336)

* Fix crashes and unbounded memory in disk cache trimming

trimToSize:, trimToSizeByEvictionStrategy:, and trimToDate: sorted the
entire metadata dictionary with keysSortedByValueUsingComparator:, which
materializes O(N) temporary storage inside CoreFoundation. On large
caches under memory pressure that allocation fails and traps in
__CFCreateArrayStorage — and since every subsequent trim hits the same
wall, a cache that grows too big to sort can never shrink again.

- Select eviction candidates in bounded 256-key batches (single pass,
  binary-search insertion, O(batch) memory) and loop until under the
  byte target, so trims always make progress. An attempted-keys set
  guarantees termination when eviction declines ghost entries.
- trimToDate: is a pure threshold filter; drop its sort entirely.
- Nil-safe comparators: metadata dates/size are nil when
  resourceValuesForKeys: fails during the initial disk scan.
  [NSNumber compare:nil] RAISES NSInvalidArgumentException (a real crash
  in trimToSize:), and [NSDate compare:nil] returns NSOrderedSame, which
  made the sorts weakly inconsistent. Unknown-metadata entries now sort
  first and are evicted before entries with known access times.
- Guard NSUInteger underflow in the trim loops: stale metadata sizes
  overshooting byteCount made the break condition unsatisfiable and
  evicted the entire cache.

Adds a multi-batch trim regression test (300 entries > one batch).

* Fix CI for current macos-latest runner image (macOS 26)

CI was failing at the first xcrun/xcodebuild invocation with
"xcrun: error: missing DEVELOPER_DIR path: /Applications/Xcode_15.2.app".
Root cause: GitHub's macos-latest label now resolves to the macOS 26
runner image, which only ships Xcode 26.x — the pinned Xcode 15.2 (and
several other things the build relied on) no longer exist on the image.

Changes, following TextureGroup/Texture's CI setup:

- DEVELOPER_DIR now points at Xcode_26.5.0.app (the image default;
  see the runner-images manifest linked in the workflow comment).
- Makefile simulator destination bumped from "iPhone 15" to
  "iPhone 17", since the iPhone 15 simulator does not exist under
  Xcode 26 on the image.
- xcpretty replaced with xcbeautify: the runner images stopped
  preinstalling the xcpretty gem (macOS 26 ships only xcbeautify
  3.2.1), so the "xcodebuild | xcpretty" pipes would fail with
  command-not-found. Error propagation is unchanged — the Makefile's
  "SHELL=/bin/bash -o pipefail" still surfaces xcodebuild failures
  through the pipe.
- Removed the platform matrix from the test job; nothing ever
  referenced matrix.platform (the Makefile owns the destination).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Dan Reed <dreed@pinterest.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

releases/p14.36

Toggle releases/p14.36's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fix crashes and unbounded memory in disk cache trimming (#336)

* Fix crashes and unbounded memory in disk cache trimming

trimToSize:, trimToSizeByEvictionStrategy:, and trimToDate: sorted the
entire metadata dictionary with keysSortedByValueUsingComparator:, which
materializes O(N) temporary storage inside CoreFoundation. On large
caches under memory pressure that allocation fails and traps in
__CFCreateArrayStorage — and since every subsequent trim hits the same
wall, a cache that grows too big to sort can never shrink again.

- Select eviction candidates in bounded 256-key batches (single pass,
  binary-search insertion, O(batch) memory) and loop until under the
  byte target, so trims always make progress. An attempted-keys set
  guarantees termination when eviction declines ghost entries.
- trimToDate: is a pure threshold filter; drop its sort entirely.
- Nil-safe comparators: metadata dates/size are nil when
  resourceValuesForKeys: fails during the initial disk scan.
  [NSNumber compare:nil] RAISES NSInvalidArgumentException (a real crash
  in trimToSize:), and [NSDate compare:nil] returns NSOrderedSame, which
  made the sorts weakly inconsistent. Unknown-metadata entries now sort
  first and are evicted before entries with known access times.
- Guard NSUInteger underflow in the trim loops: stale metadata sizes
  overshooting byteCount made the break condition unsatisfiable and
  evicted the entire cache.

Adds a multi-batch trim regression test (300 entries > one batch).

* Fix CI for current macos-latest runner image (macOS 26)

CI was failing at the first xcrun/xcodebuild invocation with
"xcrun: error: missing DEVELOPER_DIR path: /Applications/Xcode_15.2.app".
Root cause: GitHub's macos-latest label now resolves to the macOS 26
runner image, which only ships Xcode 26.x — the pinned Xcode 15.2 (and
several other things the build relied on) no longer exist on the image.

Changes, following TextureGroup/Texture's CI setup:

- DEVELOPER_DIR now points at Xcode_26.5.0.app (the image default;
  see the runner-images manifest linked in the workflow comment).
- Makefile simulator destination bumped from "iPhone 15" to
  "iPhone 17", since the iPhone 15 simulator does not exist under
  Xcode 26 on the image.
- xcpretty replaced with xcbeautify: the runner images stopped
  preinstalling the xcpretty gem (macOS 26 ships only xcbeautify
  3.2.1), so the "xcodebuild | xcpretty" pipes would fail with
  command-not-found. Error propagation is unchanged — the Makefile's
  "SHELL=/bin/bash -o pipefail" still surfaces xcodebuild failures
  through the pipe.
- Removed the platform matrix from the test job; nothing ever
  referenced matrix.platform (the Makefile owns the destination).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Dan Reed <dreed@pinterest.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

releases/p14.35

Toggle releases/p14.35's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fix crashes and unbounded memory in disk cache trimming (#336)

* Fix crashes and unbounded memory in disk cache trimming

trimToSize:, trimToSizeByEvictionStrategy:, and trimToDate: sorted the
entire metadata dictionary with keysSortedByValueUsingComparator:, which
materializes O(N) temporary storage inside CoreFoundation. On large
caches under memory pressure that allocation fails and traps in
__CFCreateArrayStorage — and since every subsequent trim hits the same
wall, a cache that grows too big to sort can never shrink again.

- Select eviction candidates in bounded 256-key batches (single pass,
  binary-search insertion, O(batch) memory) and loop until under the
  byte target, so trims always make progress. An attempted-keys set
  guarantees termination when eviction declines ghost entries.
- trimToDate: is a pure threshold filter; drop its sort entirely.
- Nil-safe comparators: metadata dates/size are nil when
  resourceValuesForKeys: fails during the initial disk scan.
  [NSNumber compare:nil] RAISES NSInvalidArgumentException (a real crash
  in trimToSize:), and [NSDate compare:nil] returns NSOrderedSame, which
  made the sorts weakly inconsistent. Unknown-metadata entries now sort
  first and are evicted before entries with known access times.
- Guard NSUInteger underflow in the trim loops: stale metadata sizes
  overshooting byteCount made the break condition unsatisfiable and
  evicted the entire cache.

Adds a multi-batch trim regression test (300 entries > one batch).

* Fix CI for current macos-latest runner image (macOS 26)

CI was failing at the first xcrun/xcodebuild invocation with
"xcrun: error: missing DEVELOPER_DIR path: /Applications/Xcode_15.2.app".
Root cause: GitHub's macos-latest label now resolves to the macOS 26
runner image, which only ships Xcode 26.x — the pinned Xcode 15.2 (and
several other things the build relied on) no longer exist on the image.

Changes, following TextureGroup/Texture's CI setup:

- DEVELOPER_DIR now points at Xcode_26.5.0.app (the image default;
  see the runner-images manifest linked in the workflow comment).
- Makefile simulator destination bumped from "iPhone 15" to
  "iPhone 17", since the iPhone 15 simulator does not exist under
  Xcode 26 on the image.
- xcpretty replaced with xcbeautify: the runner images stopped
  preinstalling the xcpretty gem (macOS 26 ships only xcbeautify
  3.2.1), so the "xcodebuild | xcpretty" pipes would fail with
  command-not-found. Error propagation is unchanged — the Makefile's
  "SHELL=/bin/bash -o pipefail" still surfaces xcodebuild failures
  through the pipe.
- Removed the platform matrix from the test job; nothing ever
  referenced matrix.platform (the Makefile owns the destination).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Dan Reed <dreed@pinterest.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

releases/p14.34

Toggle releases/p14.34's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fix crashes and unbounded memory in disk cache trimming (#336)

* Fix crashes and unbounded memory in disk cache trimming

trimToSize:, trimToSizeByEvictionStrategy:, and trimToDate: sorted the
entire metadata dictionary with keysSortedByValueUsingComparator:, which
materializes O(N) temporary storage inside CoreFoundation. On large
caches under memory pressure that allocation fails and traps in
__CFCreateArrayStorage — and since every subsequent trim hits the same
wall, a cache that grows too big to sort can never shrink again.

- Select eviction candidates in bounded 256-key batches (single pass,
  binary-search insertion, O(batch) memory) and loop until under the
  byte target, so trims always make progress. An attempted-keys set
  guarantees termination when eviction declines ghost entries.
- trimToDate: is a pure threshold filter; drop its sort entirely.
- Nil-safe comparators: metadata dates/size are nil when
  resourceValuesForKeys: fails during the initial disk scan.
  [NSNumber compare:nil] RAISES NSInvalidArgumentException (a real crash
  in trimToSize:), and [NSDate compare:nil] returns NSOrderedSame, which
  made the sorts weakly inconsistent. Unknown-metadata entries now sort
  first and are evicted before entries with known access times.
- Guard NSUInteger underflow in the trim loops: stale metadata sizes
  overshooting byteCount made the break condition unsatisfiable and
  evicted the entire cache.

Adds a multi-batch trim regression test (300 entries > one batch).

* Fix CI for current macos-latest runner image (macOS 26)

CI was failing at the first xcrun/xcodebuild invocation with
"xcrun: error: missing DEVELOPER_DIR path: /Applications/Xcode_15.2.app".
Root cause: GitHub's macos-latest label now resolves to the macOS 26
runner image, which only ships Xcode 26.x — the pinned Xcode 15.2 (and
several other things the build relied on) no longer exist on the image.

Changes, following TextureGroup/Texture's CI setup:

- DEVELOPER_DIR now points at Xcode_26.5.0.app (the image default;
  see the runner-images manifest linked in the workflow comment).
- Makefile simulator destination bumped from "iPhone 15" to
  "iPhone 17", since the iPhone 15 simulator does not exist under
  Xcode 26 on the image.
- xcpretty replaced with xcbeautify: the runner images stopped
  preinstalling the xcpretty gem (macOS 26 ships only xcbeautify
  3.2.1), so the "xcodebuild | xcpretty" pipes would fail with
  command-not-found. Error propagation is unchanged — the Makefile's
  "SHELL=/bin/bash -o pipefail" still surfaces xcodebuild failures
  through the pipe.
- Removed the platform matrix from the test job; nothing ever
  referenced matrix.platform (the Makefile owns the destination).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Dan Reed <dreed@pinterest.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

releases/p14.33

Toggle releases/p14.33's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fix crashes and unbounded memory in disk cache trimming (#336)

* Fix crashes and unbounded memory in disk cache trimming

trimToSize:, trimToSizeByEvictionStrategy:, and trimToDate: sorted the
entire metadata dictionary with keysSortedByValueUsingComparator:, which
materializes O(N) temporary storage inside CoreFoundation. On large
caches under memory pressure that allocation fails and traps in
__CFCreateArrayStorage — and since every subsequent trim hits the same
wall, a cache that grows too big to sort can never shrink again.

- Select eviction candidates in bounded 256-key batches (single pass,
  binary-search insertion, O(batch) memory) and loop until under the
  byte target, so trims always make progress. An attempted-keys set
  guarantees termination when eviction declines ghost entries.
- trimToDate: is a pure threshold filter; drop its sort entirely.
- Nil-safe comparators: metadata dates/size are nil when
  resourceValuesForKeys: fails during the initial disk scan.
  [NSNumber compare:nil] RAISES NSInvalidArgumentException (a real crash
  in trimToSize:), and [NSDate compare:nil] returns NSOrderedSame, which
  made the sorts weakly inconsistent. Unknown-metadata entries now sort
  first and are evicted before entries with known access times.
- Guard NSUInteger underflow in the trim loops: stale metadata sizes
  overshooting byteCount made the break condition unsatisfiable and
  evicted the entire cache.

Adds a multi-batch trim regression test (300 entries > one batch).

* Fix CI for current macos-latest runner image (macOS 26)

CI was failing at the first xcrun/xcodebuild invocation with
"xcrun: error: missing DEVELOPER_DIR path: /Applications/Xcode_15.2.app".
Root cause: GitHub's macos-latest label now resolves to the macOS 26
runner image, which only ships Xcode 26.x — the pinned Xcode 15.2 (and
several other things the build relied on) no longer exist on the image.

Changes, following TextureGroup/Texture's CI setup:

- DEVELOPER_DIR now points at Xcode_26.5.0.app (the image default;
  see the runner-images manifest linked in the workflow comment).
- Makefile simulator destination bumped from "iPhone 15" to
  "iPhone 17", since the iPhone 15 simulator does not exist under
  Xcode 26 on the image.
- xcpretty replaced with xcbeautify: the runner images stopped
  preinstalling the xcpretty gem (macOS 26 ships only xcbeautify
  3.2.1), so the "xcodebuild | xcpretty" pipes would fail with
  command-not-found. Error propagation is unchanged — the Makefile's
  "SHELL=/bin/bash -o pipefail" still surfaces xcodebuild failures
  through the pipe.
- Removed the platform matrix from the test job; nothing ever
  referenced matrix.platform (the Makefile owns the destination).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Dan Reed <dreed@pinterest.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

releases/p14.32

Toggle releases/p14.32's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fix crashes and unbounded memory in disk cache trimming (#336)

* Fix crashes and unbounded memory in disk cache trimming

trimToSize:, trimToSizeByEvictionStrategy:, and trimToDate: sorted the
entire metadata dictionary with keysSortedByValueUsingComparator:, which
materializes O(N) temporary storage inside CoreFoundation. On large
caches under memory pressure that allocation fails and traps in
__CFCreateArrayStorage — and since every subsequent trim hits the same
wall, a cache that grows too big to sort can never shrink again.

- Select eviction candidates in bounded 256-key batches (single pass,
  binary-search insertion, O(batch) memory) and loop until under the
  byte target, so trims always make progress. An attempted-keys set
  guarantees termination when eviction declines ghost entries.
- trimToDate: is a pure threshold filter; drop its sort entirely.
- Nil-safe comparators: metadata dates/size are nil when
  resourceValuesForKeys: fails during the initial disk scan.
  [NSNumber compare:nil] RAISES NSInvalidArgumentException (a real crash
  in trimToSize:), and [NSDate compare:nil] returns NSOrderedSame, which
  made the sorts weakly inconsistent. Unknown-metadata entries now sort
  first and are evicted before entries with known access times.
- Guard NSUInteger underflow in the trim loops: stale metadata sizes
  overshooting byteCount made the break condition unsatisfiable and
  evicted the entire cache.

Adds a multi-batch trim regression test (300 entries > one batch).

* Fix CI for current macos-latest runner image (macOS 26)

CI was failing at the first xcrun/xcodebuild invocation with
"xcrun: error: missing DEVELOPER_DIR path: /Applications/Xcode_15.2.app".
Root cause: GitHub's macos-latest label now resolves to the macOS 26
runner image, which only ships Xcode 26.x — the pinned Xcode 15.2 (and
several other things the build relied on) no longer exist on the image.

Changes, following TextureGroup/Texture's CI setup:

- DEVELOPER_DIR now points at Xcode_26.5.0.app (the image default;
  see the runner-images manifest linked in the workflow comment).
- Makefile simulator destination bumped from "iPhone 15" to
  "iPhone 17", since the iPhone 15 simulator does not exist under
  Xcode 26 on the image.
- xcpretty replaced with xcbeautify: the runner images stopped
  preinstalling the xcpretty gem (macOS 26 ships only xcbeautify
  3.2.1), so the "xcodebuild | xcpretty" pipes would fail with
  command-not-found. Error propagation is unchanged — the Makefile's
  "SHELL=/bin/bash -o pipefail" still surfaces xcodebuild failures
  through the pipe.
- Removed the platform matrix from the test job; nothing ever
  referenced matrix.platform (the Makefile owns the destination).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Dan Reed <dreed@pinterest.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

3.0.4

Toggle 3.0.4's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Cut 3.0.4 release #changelog (#331)

## Summary

Need to cut the 3.0.4 release now that everything has been merged.