Skip to content

Add failed request diagnostics#750

Merged
tillkruss merged 11 commits into
developfrom
feature/http-diagnostics
Jul 25, 2026
Merged

Add failed request diagnostics#750
tillkruss merged 11 commits into
developfrom
feature/http-diagnostics

Conversation

@tillkruss

@tillkruss tillkruss commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

Adds a Failed Requests section to the Diagnostics screen (Settings → Diagnostics) listing recent failed HTTP requests, and refactors the screen and its shareable .txt export to render from a single model.

Failed request capture

  • API.request now records failures into RequestDiagnostics — an in-memory, session-scoped ring buffer (most recent 50; consecutive duplicates collapsed).
  • Captures server error responses (4xx/5xx), transport failures (timeouts, connection/DNS), JSON decoding failures, and other pre-flight errors such as body encoding — everything except user cancellations.
  • URLs are masked by default and honor the diagnostics eye toggle; failures are included in the shared export.

Single-source diagnostics model

  • The screen and the .txt export both render from one DiagnosticsReport (DiagnosticsModel.swift) — adding a diagnostic is a single DiagnosticRow, and masking is centralized in DiagnosticValue.
  • Removes the duplicated NetworkReport.exportText / AppDiagnostics.exportLines / view-side export code that had to be hand-kept in sync. Screen visuals are unchanged; the export is slightly cleaner (separate [Device] / [Network] blocks).

Tests

  • RequestDiagnosticsTests covers newest-first ordering, consecutive-duplicate collapsing, the 50-entry cap, and blank-instance handling. The store is decoupled from API.Error (mapping moved to RequestDiagnostics+API.swift) so it fits the Foundation-only Tests target.

Copilot AI review requested due to automatic review settings July 25, 2026 00:58

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 09949728a5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Ruddarr/Views/Settings/DiagnosticsView.swift Outdated
Comment thread Ruddarr/Views/Settings/DiagnosticsView.swift Outdated
Comment thread Ruddarr/Dependencies/API/API.swift

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a lightweight request-failure diagnostics pipeline that records recent API failures and surfaces them in the Settings → Diagnostics screen and the exported diagnostics text, improving post-mortem troubleshooting.

Changes:

  • Introduces RequestDiagnostics (actor) and FailedRequest model to record recent failed API requests.
  • Hooks API error paths to record failures and exposes them in DiagnosticsView (UI + export).
  • Extends NetworkReport.exportText(...) to include failed-request export lines.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

File Description
Ruddarr/Views/Settings/DiagnosticsView.swift Adds a “Failed Requests” section and includes failed requests in the shared diagnostics export.
Ruddarr/Utilities/RequestDiagnostics.swift New actor + data model for recording and snapshotting recent failed requests.
Ruddarr/Utilities/NetworkReport.swift Extends diagnostics export to accept and append failed-request lines.
Ruddarr/Dependencies/API/API.swift Records API failures to RequestDiagnostics when requests throw.
Comments suppressed due to low confidence (2)

Ruddarr/Views/Settings/DiagnosticsView.swift:169

  • This adds user-facing diagnostics output (new Failed Requests section and inclusion in the shared export), but the PR doesn’t include the required release-note updates. Per AGENTS.md, user-facing changes must update CHANGELOG.md (Unreleased) and keep TestFlight/WhatToTest.en-US.txt in sync with Unreleased.
                    if candidate.hasHostname {
                        networkDiagnosticsRow("Resolved IPs", candidateAddressesText(candidate))
                    }

                    if candidate.probeDescription != nil {

Ruddarr/Views/Settings/DiagnosticsView.swift:366

  • Even with masking enabled, the displayed/exported failed-request URL will include the full query string because maskedURL(...) preserves percentEncodedQuery. That can leak sensitive query parameters in “masked” diagnostics (e.g. tokens embedded in URLs).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Ruddarr/Utilities/RequestDiagnostics.swift Outdated
Comment thread Ruddarr/Dependencies/API/API.swift
Copilot AI review requested due to automatic review settings July 25, 2026 01:03

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Comment thread Ruddarr/Views/Settings/DiagnosticsView.swift Outdated
Comment thread Ruddarr/Views/Settings/DiagnosticsView.swift
Copilot AI review requested due to automatic review settings July 25, 2026 01:30
@tillkruss tillkruss changed the title wip Add failed request diagnostics Jul 25, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

Ruddarr/Views/Settings/DiagnosticsView.swift:117

  • This adds a user-facing Diagnostics screen section (“Failed Requests”). Per AGENTS.md, user-facing changes must include a CHANGELOG.md entry under Unreleased, and TestFlight/WhatToTest.en-US.txt should match Unreleased. Those updates aren’t included in this PR diff.
                    requestRow(request)
                }
            } header: {
                Text(verbatim: "Failed Requests")
            }

Comment thread Ruddarr/Utilities/RequestDiagnostics.swift
Comment thread Ruddarr/Utilities/RequestDiagnostics+API.swift Outdated
Copilot AI review requested due to automatic review settings July 25, 2026 02:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

Ruddarr/Views/Settings/DiagnosticsView.swift:116

  • This adds a new user-facing Diagnostics section (“Failed Requests”). Per AGENTS.md, user-facing changes should be reflected in CHANGELOG.md (Unreleased) and mirrored in TestFlight/WhatToTest.en-US.txt, but those files don’t appear to include an entry for this change.
                Text(verbatim: "Failed Requests")

Comment thread Ruddarr/Utilities/RequestDiagnostics.swift Outdated
Copilot AI review requested due to automatic review settings July 25, 2026 02:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Comment thread Ruddarr/Views/Settings/DiagnosticsView.swift Outdated
Comment on lines 110 to 114
if !failedRequests.isEmpty {
Section {
networkDiagnosticsRow("IPv4 Address", mask.list(report.deviceV4.map { mask.ip(NetworkInterfaces.string(fromIPv4: $0.address)) }))
networkDiagnosticsRow("IPv4 Subnets", report.subnetRowsV4(mask))

if !report.deviceV6.isEmpty {
networkDiagnosticsRow("IPv6 Address", mask.list(report.deviceV6.map { mask.ip(NetworkInterfaces.string(fromIPv6Bytes: $0.address)) }))
networkDiagnosticsRow("IPv6 Subnets", report.subnetRowsV6(mask))
ForEach(failedRequests) { request in
requestRow(request)
}
Comment on lines +48 to +54
private static func deviceSection(_ report: NetworkReport) -> FieldSection {
FieldSection("Device", [
DiagnosticRow("Connection", .plain(report.connection)),
DiagnosticRow("Low Data Mode", .plain(report.constrained ? "on" : "off"), appearance: .exportOnly),
DiagnosticRow("Local Network", .plain(report.localNetworkDenied ? "denied" : "allowed")),
DiagnosticRow("Tailscale", .plain(report.tailnetUp ? "up" : "down")),
])
Comment thread Ruddarr/Utilities/DiagnosticsExport.swift
Copilot AI review requested due to automatic review settings July 25, 2026 02:40

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

.truncationMode(.middle)

if let detail = request.detail, !detail.isEmpty {
Text(verbatim: masked ? maskURLs(in: detail) : detail)
lines.append(" URL: \(mask.url(request.url))")

if let detail = request.detail, !detail.isEmpty {
lines.append(" Error: \(mask.masked ? maskURLs(in: detail) : detail)")
Comment thread Ruddarr/Views/Settings/DiagnosticsView.swift
Copilot AI review requested due to automatic review settings July 25, 2026 03:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

Ruddarr/Views/Settings/DiagnosticsView.swift:113

  • This PR adds a new user-facing “Failed Requests” diagnostics section, but there’s no corresponding entry in CHANGELOG.md (Unreleased) and TestFlight/WhatToTest.en-US.txt currently doesn’t mention it. Repo guidance requires updating both for user-facing changes.
                Text(verbatim: "Failed Requests")

Comment on lines +83 to +87
} catch let error as CancellationError {
throw error
} catch API.Error.notConnectedToInternet {
throw API.Error.notConnectedToInternet
} catch {
Copilot AI review requested due to automatic review settings July 25, 2026 03:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

Ruddarr/Dependencies/API/API.swift:87

  • API.request currently rethrows API.Error.notConnectedToInternet before the diagnostics recording block, so these transport failures never appear in the new “Failed Requests” diagnostics (and won’t be included in the shared export) even though the PR description says transport failures are captured. Let this error fall through to the recording catch so it’s recorded while still being rethrown unchanged.
        } catch let error as CancellationError {
            throw error
        } catch API.Error.notConnectedToInternet {
            throw API.Error.notConnectedToInternet
        } catch {

Ruddarr/Views/Settings/DiagnosticsView.swift:114

  • This is a user-facing change (new “Failed Requests” section under Settings → Diagnostics). Per AGENTS.md, user-facing changes must add a CHANGELOG.md entry under Unreleased and keep TestFlight/WhatToTest.en-US.txt in sync with Unreleased. Those files don’t currently mention this feature, so the release notes need updating before merge.
    @ViewBuilder
    func requestsSection(_ requests: [FailedRequest]) -> some View {
        if !requests.isEmpty {
            Section {
                ForEach(requests) { request in
                    requestRow(request)
                }
            } header: {
                Text(verbatim: "Failed Requests")
            }

Ruddarr/Utilities/DiagnosticsExport.swift:10

  • DiagnosticsExport.text(from:masked:) is now the single source for the shareable diagnostics format (including the new Failed Requests block and masking behavior), but there are no tests asserting the exported text structure/content. Adding a focused test would help prevent accidental regressions to the export format and privacy masking.
enum DiagnosticsExport {
    static func text(from report: DiagnosticsReport, masked: Bool) -> String {
        var lines: [String] = ["# Ruddarr Diagnostics"]

        if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String,
           let build = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String {
            lines.append("Version: \(version) (\(build))")
        }

@tillkruss
tillkruss merged commit e1a1952 into develop Jul 25, 2026
8 checks passed
@tillkruss
tillkruss deleted the feature/http-diagnostics branch July 25, 2026 03:41
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.

2 participants