Skip to content

cleanup(ios): make elapsedRealtimeMillis count through device sleep - #1328

Merged
9thLevelSoftware merged 2 commits into
mainfrom
cursor/ios-elapsed-realtime-sleep-1021
Oct 23, 2026
Merged

9thLevelSoftware merged 2 commits into
mainfrom
cursor/ios-elapsed-realtime-sleep-1021

Conversation

@9thLevelSoftware

@9thLevelSoftware 9thLevelSoftware commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

Problem

iOS elapsedRealtimeMillis used NSProcessInfo.systemUptime, which stops while the device sleeps. Android uses SystemClock.elapsedRealtime(), which keeps counting. Live rest deadlines (including Just Lift) are armed on this clock, so a locked iPhone under-counted rest until the process was killed and restored from the wall-clock deadline.

Fix

The iOS actual now reads Darwin CLOCK_MONOTONIC_RAW via clock_gettime_nsec_np. Apple Libc gen/clock_gettime.c reads that clock id from mach_continuous_time(), which includes time spent asleep (CLOCK_UPTIME_RAW is the mach_absolute_time() one that stops). The KDoc cites this. Units stay milliseconds and the expect signature is unchanged. The common KDoc now says the clock includes sleep, matching Android.

Verification

./gradlew :shared:compileKotlinIosSimulatorArm64 :shared:compileTestKotlinIosSimulatorArm64 :shared:compileAndroidHostTest :androidApp:compileDebugKotlin -Pskip.supabase.check=true

The new iosTest is a smoke check only: the reading is boot-relative, does not go backwards, and is not wall-clock time. The simulator cannot be put to sleep in that test, so it does not distinguish the sleep-inclusive clock from the awake-only one. A before/after-sleep reading on a physical iPhone is still unverified.

NSProcessInfo.systemUptime pauses while the phone is asleep, so rest
deadlines armed on that clock under-counted until the process was
restored. Use Darwin CLOCK_MONOTONIC_RAW, which follows
mach_continuous_time and keeps counting through sleep.

Co-authored-by: Devil <9thLevelSoftware@users.noreply.github.com>
@9thLevelSoftware
9thLevelSoftware marked this pull request as ready for review October 23, 2026 14:31
Copilot AI balanced review requested due to automatic review settings October 23, 2026 14:31

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@kilo-code-bot

kilo-code-bot Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 2 Issues Found | Recommendation: Merge (already merged) — one follow-up verification outstanding

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
shared/src/iosMain/kotlin/com/devil/phoenixproject/domain/model/PlatformUtils.ios.kt 19 The Darwin mapping is now cited to Apple Libc gen/clock_gettime.c, but the sleep-inclusive behavior still has no physical-device measurement, and this sandbox blocks outbound reads, so the cited mapping could not be independently re-verified here.
shared/src/iosMain/kotlin/com/devil/phoenixproject/domain/model/PlatformUtils.ios.kt 24 .convert() plus the UnsafeNumber opt-in are a no-op when CLOCK_MONOTONIC_RAW is already clockid_t (optional cleanup).
Files Reviewed (3 files)
  • shared/src/commonMain/kotlin/com/devil/phoenixproject/domain/model/PlatformUtils.kt - 0 issues (unchanged in this pass; KDoc now matches the new iOS actual)
  • shared/src/iosMain/kotlin/com/devil/phoenixproject/domain/model/PlatformUtils.ios.kt - 2 issues
  • shared/src/iosTest/kotlin/com/devil/phoenixproject/domain/model/ElapsedRealtimeIosTest.kt - 0 issues (previous finding resolved)

Fix these issues in Kilo Cloud

Verdict

Comment only — the incremental commit resolves both prior findings in the direction the review asked for, and no new defect appears in the changed lines; the one open item is a physical-device measurement that cannot be produced in this environment.

Correctness / Safety Findings

important: shared/src/iosMain/kotlin/com/devil/phoenixproject/domain/model/PlatformUtils.ios.kt:L19: the previous finding is now half-closed — the KDoc cites Apple Libc gen/clock_gettime.c and states the CLOCK_MONOTONIC_RAW → mach_continuous_time() (counts while asleep) / CLOCK_UPTIME_RAW → mach_absolute_time() (stops while asleep) mapping, and the PR description now states plainly that the sleep-inclusive property is unverified on hardware. What remains is the measurement itself: this sandbox rejects outbound HTTP, so the cited Apple source could not be re-read to confirm the mapping, and nothing in the repo distinguishes the two clocks (the simulator test is explicitly a smoke check, and iosSimulatorArm64Test runs only on push to main / manual dispatch and is non-blocking, so it gives no PR-time signal either). Required fix: record elapsedRealtimeMillis() sampled before and after a 5-minute sleep on a physical iPhone; if the delta excludes the sleep time, the id is wrong and the original under-count ships.

No new correctness, safety, or regression issues in the changed lines of this pass. The trimmed test no longer imports NSProcessInfo, keeps every symbol it uses (WALL_CLOCK_MS is still referenced at line 22), drops the constant and assertion that also held for the pre-fix implementation, and the file's own KDoc plus the PR description now describe it accurately as a smoke check. elapsedRealtimeMillis() remains an in-memory-only clock: persisted rest deadlines still use wall clock (restDeadlineEpochMs / RestDeadlineCalculator), restDeadlineElapsedRealtimeMs and justLiftRestDeadlineElapsedRealtimeMs are never persisted, and the boot-relative millisecond epoch is unchanged from the old systemUptime value, so the common KDoc claim ("milliseconds since boot ... including time spent in sleep", matching Android SystemClock.elapsedRealtime()) holds on both platforms. The reviewed content is what landed: the PR head 82e615ac was squash-merged as cf8f0166.

Ponytail Review

shared/src/iosTest/kotlin/com/devil/phoenixproject/domain/model/ElapsedRealtimeIosTest.kt:L27: test-shrink — 31 lines and three assertions that also hold for the pre-fix systemUptime implementation. Inline the threshold, drop the companion object, or delete the file if a device-only sleep check lands elsewhere. (optional)

shared/src/iosMain/kotlin/com/devil/phoenixproject/domain/model/PlatformUtils.ios.kt:L24: shrink — .convert() plus the UnsafeNumber opt-in are a no-op if CLOCK_MONOTONIC_RAW is already clockid_t (Int on Darwin). Verify the binding type, then pass the constant directly and drop the convert/UnsafeNumber imports. (optional, carried from the previous review)

Ponytail net: -6 lines.

Suggested Minimal Patch

  1. PlatformUtils.ios.kt: if CLOCK_MONOTONIC_RAW is already clockid_t, remove .convert(), the UnsafeNumber opt-in, and the two now-unused imports.
  2. ElapsedRealtimeIosTest.kt: inline WALL_CLOCK_MS and delete the companion object, or delete the file once the device-only check exists.
  3. Record the device before/after-sleep readings in the PR (or a follow-up issue) so the cited mapping has a measured counterpart.

No new dependencies, no other files touched.

Final Merge Guidance

Already merged as cf8f0166; no merge-blocking defect in the changed lines. The only outstanding action is a follow-up measurement on a physical iPhone before relying on the sleep-inclusive behavior — until then, treat the Darwin mapping as cited but unmeasured.

Previous Review Summary (commit 849f3e1)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 849f3e1)

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
shared/src/iosMain/kotlin/com/devil/phoenixproject/domain/model/PlatformUtils.ios.kt 20 Darwin clock-id semantics are asserted, not verified: nothing in the repo establishes that CLOCK_MONOTONIC_RAW counts through sleep. Needs a cited Apple/XNU source plus a device measurement across a sleep cycle.
shared/src/iosTest/kotlin/com/devil/phoenixproject/domain/model/ElapsedRealtimeIosTest.kt 27 Every assertion also passes with the pre-fix NSProcessInfo.systemUptime implementation, so the new test gives no regression protection for the sleep-inclusive clock.
Files Reviewed (3 files)
  • shared/src/commonMain/kotlin/com/devil/phoenixproject/domain/model/PlatformUtils.kt - 0 issues
  • shared/src/iosMain/kotlin/com/devil/phoenixproject/domain/model/PlatformUtils.ios.kt - 1 issue
  • shared/src/iosTest/kotlin/com/devil/phoenixproject/domain/model/ElapsedRealtimeIosTest.kt - 1 issue

Fix these issues in Kilo Cloud

Verdict

Request changes — the change is small and the intent is right, but the platform-clock behavior it depends on is uncited and the only new test passes with the code it replaces.

Correctness / Safety Findings

important: shared/src/iosMain/kotlin/com/devil/phoenixproject/domain/model/PlatformUtils.ios.kt:L20: the fix hinges on CLOCK_MONOTONIC_RAW counting sleep on Darwin, a claim carried only by the new KDoc. Darwin's POSIX clock ids are not Linux-compatible (CLOCK_UPTIME_RAW is the awake-uptime clock), so a wrong pick keeps the original under-count. Add the Apple/XNU citation to the KDoc and paste before/after values sampled across a real device sleep; use the Apple-documented sleep-inclusive clock (mach_continuous_time) if the mapping turns out to be the awake-uptime one.

important: shared/src/iosTest/kotlin/com/devil/phoenixproject/domain/model/ElapsedRealtimeIosTest.kt:L27: NSProcessInfo.systemUptime * 1000 equals awakeUptimeMs, so the pre-fix implementation satisfies all four assertions and the test protects nothing. Add a device-only before/after-sleep comparison or trim the file to one smoke assertion; also drop the "is at least the awake uptime" claim from the PR description.

No other correctness, safety, or regression issues found: the clock is only used for in-memory deadlines (restDeadlineElapsedRealtimeMs, justLiftRestDeadlineElapsedRealtimeMs, armRestDeadline), persisted deadlines still use wall clock, and no Swift or Android app code reads systemUptime, so the epoch and unit contract stay intact.

Ponytail Review

shared/src/iosTest/kotlin/com/devil/phoenixproject/domain/model/ElapsedRealtimeIosTest.kt:L13: test-shrink — 37 lines and four assertions that also pass with the pre-fix implementation. Replace with one smoke assertion on the iOS actual (or delete the file if the device-only sleep check lands elsewhere).

shared/src/iosMain/kotlin/com/devil/phoenixproject/domain/model/PlatformUtils.ios.kt:L20: shrink — .convert() plus the UnsafeNumber opt-in are a no-op if CLOCK_MONOTONIC_RAW is already clockid_t (Int on Darwin). Verify the binding type, then pass the constant directly and drop the convert/UnsafeNumber imports. (optional)

Ponytail net: -25 lines.

Suggested Minimal Patch

  1. PlatformUtils.ios.kt: add the Apple/XNU citation for the CLOCK_MONOTONIC_RAW mapping to the existing KDoc; drop .convert() and the UnsafeNumber import if the constant is already clockid_t.
  2. ElapsedRealtimeIosTest.kt: keep a single boot-relative smoke assertion, or delete the file if a device-only sleep check is added. No new dependencies, no other files touched.

Final Merge Guidance

Can merge once the Darwin clock mapping is cited and the new test either covers the sleep-inclusive clock or is trimmed — the implementation itself is sound and small.


Reviewed by minimax-m3 · Input: 202.9K · Output: 163.1K · Cached: 2M

Review guidance: REVIEW.md from base branch main

…st a smoke check

The KDoc now cites Apple Libc gen/clock_gettime.c: CLOCK_MONOTONIC_RAW reads
mach_continuous_time() (counts through sleep), CLOCK_UPTIME_RAW reads
mach_absolute_time() (stops while asleep).

The "at least the awake uptime" assertion also held for the old
NSProcessInfo.systemUptime implementation, so it could not catch a
regression. Drop it and say plainly that the simulator test is a smoke check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015tsDJ6LzV6FwGD3VQwfNEn
@9thLevelSoftware
9thLevelSoftware merged commit cf8f016 into main Oct 23, 2026
11 checks passed
@9thLevelSoftware
9thLevelSoftware deleted the cursor/ios-elapsed-realtime-sleep-1021 branch October 23, 2026 17:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants