Skip to content

Harden the Custom Metrics file importer - #72

Open
Kyome22 wants to merge 1 commit into
mainfrom
harden/custom-metrics-file-importer
Open

Harden the Custom Metrics file importer#72
Kyome22 wants to merge 1 commit into
mainfrom
harden/custom-metrics-file-importer

Conversation

@Kyome22

@Kyome22 Kyome22 commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Context of Contribution

  • Bug Fix
  • Refactoring
  • New Feature
  • Localization (new language or translation update)
  • Others (defensive hardening)

Summary of the Proposal

Important

This does not fully resolve #47. The root cause of that report is still unidentified, and this PR must not be treated as a fix for it. #47 should stay open until the crash is actually reproduced. See "Relation to #47" below.

Two changes to the Custom Metrics file importer, both aligning it with the custom runner importer that already exists in this codebase.

1. Use the array-based fileImporter overload.

CustomMetricsSettingsSectionView used fileImporter(isPresented:allowedContentTypes:onCompletion:), the single-selection convenience overload. SwiftUI implements it on top of the array-based one: a wrapper closure converts Result<[URL], Error> into Result<URL, Error>. Disassembling SwiftUI on macOS 26.5.2 confirms the shape of that adapter and that it reaches brk #0x1 traps from array-count comparisons.

This PR calls the array overload directly with allowsMultipleSelection: false and guards the first URL, so that adapter is never entered. CustomRunnerEditorView already does this.

CustomMetricsSettings.Action.onCompletionFileImporter therefore carries Result<[URL], any Error> instead of Result<URL, any Error>, matching CustomRunnerSettings.

2. Move the presentation modifiers off the Section.

.fileImporter, .fileDialogMessage, .fileDialogConfirmationLabel and .confirmationDialog were attached to the Section itself. Modifiers applied to a Section inside a Form can be replicated per row, which would bind several importers to the same showingFileImporter state. They now sit on the concrete HStack that holds the add button, the same way CustomRunnerSettingsSectionView attaches its .sheet to a button rather than to the section.

No user-visible behaviour changes.

Relation to #47

#47 reports an EXC_BREAKPOINT whose top frame is exactly SwiftUI's single-selection adapter, so the overload change addresses the mechanism that report points at. However, the crash could not be reproduced:

  • macOS 26.5.2 (25F84) — the exact build named in the report
  • tag 1.0.3 built from source — the exact version named in the report
  • Apple Silicon, run under lldb
  • attempted with 0, 2 and 3 existing custom metrics sources

In every attempt the import completed successfully. lldb caught no trap and no crash report was produced. The reporter has not provided the JSON file that was requested, and the stack trace in the report contains no app frames, thread numbers or exception codes.

So the trigger condition remains unknown. This PR removes a class of failure and makes the code consistent, but it is not a verified fix.

Reason for the new feature

N/A — not a new feature.

Checklist

  • I have read the CONTRIBUTING.md and agree to follow it.
  • This PR does not contain commits of multiple contexts.
  • The diff is minimal — no unrelated refactors, whitespace churn, or drive-by cleanups.
  • Code follows proper indentation and naming conventions.
  • Layering follows the LUCA architecture: no logic in DependencyClient, no logic in UserInterface views, no Asset/String Catalog references from Model.
  • Implemented using only APIs that can be submitted to the App Store.
  • Localization PRs only: Every translated string in this PR was hand-crafted by a human translator. No machine translation or LLM output was used. See CONTRIBUTING.md → Localization.

Verification

  • xcodebuild build -project RunCatNeo.xcodeproj -scheme RunCatNeo — succeeded
  • xcodebuild test -scheme LocalPackage-Package -destination 'platform=macOS,arch=arm64' — 170 tests passed (DataSourceTests 29, ModelTests 141), 0 failures
  • Added send_onCompletionFileImporter_success_without_url_is_noop, covering an empty selection
  • Manually verified in a debug build: adding a source, cancelling the panel, reordering, removing and revealing in Finder all behave as before

🤖 Generated with Claude Code

Use the array-based fileImporter overload with allowsMultipleSelection
set to false and guard the first URL, so the completion never relies on
SwiftUI's single-selection adapter. Move the file importer, the file
dialog modifiers and the confirmation dialog off the Section and onto a
concrete view, so they are not replicated per row.

This mirrors the custom runner importer, which already uses both
patterns.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

[Bug]: Crash (EXC_BREAKPOINT) when adding a Custom Metrics source via the file importer

1 participant