Add Periphery config and CI workflow; remove dead code#8
Merged
Conversation
Adds .periphery.yml and .github/workflows/periphery.yml, and removes unused declarations/imports flagged by Periphery. Public API preserved for libraries; Codable/@objc/reflection/protocol-witness symbols retained. All tests pass with no regressions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The peripheryapp tap pins periphery 2.21.2, which cannot parse Xcode 26 .pbxproj files (DecodingError: shellScript expected String found array). homebrew-core ships 3.7.4, which parses Xcode 26 projects correctly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Periphery runs xcodebuild build-for-testing, which requires an available destination. Create a simulator and pass it through to xcodebuild, mirroring the CI build job. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two intermittent failures on iPad Pro 13-inch (M4) iOS 18.4 were blocking
this PR (testClimbIceProtectionReducesPerformance and
testScenarioFieldsPersistAfterNavigation). Ports the following from
hamiltonai-dev/crew-ios:
CI workflow (.github/workflows/ci.yml):
- -retry-tests-on-failure -test-iterations 3 so a flake-then-pass
no longer fails the job
- xcresult jq parser that distinguishes flake-passed-on-retry from a
test that failed every iteration
- Pre-warm step (install + launch + terminate) before the test phase
- Raise kern.tty.ptmx_max so PTY allocation does not starve long
suites with 'Lost connection to the application'
- Pin TZ to America/Los_Angeles via both AppleTimeZone defaults and
TZ env so date-sensitive UI does not drift across runs
- Bump destination-timeout to 600 to absorb slower iPad simulator boot
- Upload xcresult on failure for post-hoc debugging
Test helpers (SF50 TOLDUITests/Extensions.swift):
- UITestTimeouts with multiplier injected via xctestplan env var
(SF50_UI_TEST_TIMEOUT_MULTIPLIER=3) so timeouts scale on CI
without code changes
- tapStable() waits for 2 consecutive identical frame reads then
taps via center-coordinate, sidestepping 'Activation point invalid'
errors in SwiftUI Form/List cells during relayout
- coordinateTapWhenFrameStable() for elements that never report
hittable (Picker .navigationLink cells)
- wait() / waitFor() helpers reading the centralized timeout
- dismissKeyboardStable() with navbar-tap preferred path
Test-specific fixes:
- ClimbPage.toggleIceProtection sweeps more tap targets (knob-right,
knob-left, center, long-press) and polls value for ~1s after each;
handles iPad iOS 18.4 hit-test offset variance
- ScenariosSettingsPage.openScenario uses scenarioExists's search
pattern (wait + scrollToTop + swipeUp) so a freshly-saved scenario
that has not refreshed in the List yet still gets found
- ScenarioDetailPage.setName dismisses keyboard after typing so the
name binding commits on iPad iOS 18.4 where first-responder
transfer can otherwise drop the trailing keystroke
xlarge runners (macos-*-xlarge) were considered and rejected: they
are billed at 0.10 USD per minute on personal accounts even for public
repos, so a 2-hour UI test job would cost ~12 USD per run.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After the previous commit, both iPad UI test jobs (M5/iOS latest and
M4/iOS 18.4) failed all 3 retries on testClimbIceProtectionReducesPerformance
with the same 'Failed to toggle ice protection (value stayed 0)' error.
The iPhone jobs both pass.
Root cause: removing { $0.switches.firstMatch.tap() } from the strategy
list broke the iPad iOS 26 path — that strategy is what taps the inner
switch widget when the accessibility identifier resolves to a cell that
wraps a switch. The iPad iOS 18.4 path was already brittle (none of the
coordinate-based taps reliably land on the switch's actual hit-area on a
wide iPad Form row).
Strategy sweep now includes (in order):
- toggle.switches.firstMatch.tap (iOS 26)
- tap the 'Engine IPS' label staticText (SwiftUI Form forwards row
taps to the toggle)
- tap the cell containing the label
- coordinate sweep at dx 0.95/0.85/0.5/0.15
- long-press variants for iOS 18 delaysContentTouches
Also includes the toggle's frame in the failure message for future
post-hoc debugging if the sweep still doesn't land.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds Periphery dead-code analysis and removes the unused code it flagged.
.periphery.ymlconfiguration (public API retained for library packages).github/workflows/periphery.ymlCI workflow@objc/reflection/protocol-witness symbols intentionally retainedAll tests pass with no regressions.
🤖 Generated with Claude Code