Skip to content

Fix scroll jitter: filter display-safety once at ingestion#31

Open
castanley wants to merge 1 commit into
b-nnett:mainfrom
castanley:fix/display-safety-render-scans
Open

Fix scroll jitter: filter display-safety once at ingestion#31
castanley wants to merge 1 commit into
b-nnett:mainfrom
castanley:fix/display-safety-render-scans

Conversation

@castanley

@castanley castanley commented Jun 10, 2026

Copy link
Copy Markdown

The forbidden-source-marker scan (localHealthMetricRowIsDisplaySafe) deep-reads every string in every metric row, and the dailyRecoveryMetrics()/dailyActivityMetrics()/hourlyActivityMetrics() getters plus the static preferred*/trendRows(from:) helpers re-run it on every call — every SwiftUI body pass of Home and Health, 2-3x per row.

Profiled on hardware (iPhone 17 Pro, release build, during a strap sync): 22 s of a 42 s main-thread CPU total was this scan. It is the dominant source of the scroll jitter in the README's performance note, and it is worst while syncing.

Metric rows are Swift value-type dictionaries with no stable object identity, so caches keyed on row/container identity never hit. This PR runs the scan exactly once — when packetInputReports is stored (didSet) — into a per-family stored array; getters return it and the redundant re-filters in the from: helpers are removed (every caller passes getter-derived, already-safe rows). Extraction runs rarely, so display-safety filtering is off the render path entirely.

Filtered output is identical; no behavior change. Verified on hardware before/after on a downstream fork: scrolling is smooth, including during sync. (Updated from an earlier per-render-cache version that didn't actually hit, for the value-type-identity reason above.)

localHealthMetricRowIsDisplaySafe deep-scans every string in every
metric row for forbidden platform-source markers, and the
dailyRecoveryMetrics()/dailyActivityMetrics()/hourlyActivityMetrics()
getters plus the static preferred*/trendRows(from:) helpers re-ran it
on every call — i.e. on every SwiftUI body pass of Home and Health,
2-3x per row. An on-device Time Profiler trace (iPhone 17 Pro, release
build, during a strap sync) attributed 22 s of a 42 s main-thread
total to this scan; it is the dominant cause of the scroll jitter the
README mentions, and it is worst while syncing.

Metric rows are Swift value-type dictionaries with no stable object
identity, so caches keyed on row/container identity never hit. Instead
the scan runs exactly once, when packetInputReports is stored (didSet),
into a per-family stored array; getters return it and the redundant
re-filters in the from: helpers are removed (every caller passes
getter-derived, already-safe rows). Extraction runs rarely, so
display-safety filtering is off the render path entirely.

Verified on hardware before/after: scrolling is smooth, including
during sync.
@castanley castanley force-pushed the fix/display-safety-render-scans branch from bb08b5e to 8fb3abe Compare June 10, 2026 15:24
@castanley castanley changed the title Fix scroll jitter: cache display-safety row filtering per report identity Fix scroll jitter: filter display-safety once at ingestion Jun 10, 2026
@castanley

Copy link
Copy Markdown
Author

Heads-up unrelated to this PR: ios_healthkit_boundary_tests (both cases) already fails on main (ba9ae02) because its swift_source_root() points at goose-swift/GooseSwift/ while the Swift sources live at GooseSwift/. That's a stale path on main, not introduced here — flagging in case CI looks red for that reason.

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.

1 participant