Skip to content

fix(loggers): extract SessionDataRepository and surface session-delete failures (#592)#607

Merged
tylerkron merged 2 commits into
mainfrom
fix/extract-session-data-repository
Jun 18, 2026
Merged

fix(loggers): extract SessionDataRepository and surface session-delete failures (#592)#607
tylerkron merged 2 commits into
mainfrom
fix/extract-session-data-repository

Conversation

@tylerkron

Copy link
Copy Markdown
Contributor

Summary

Extracts the session read/delete path out of the 1,721-line DatabaseLogger god class into a testable SessionDataRepository (the next #592 extraction), and fixes the latent delete-failure-undetected data-integrity bug the extraction unblocks.

DatabaseLogger.cs: 1,721 → 1,376 lines.

Extraction (behavior-preserving)

  • SessionDataRepository owns the EF/ADO read path — channel discovery + the fast initial batch (LoadInitialSession), the full-range sampled load (LoadSampledData), the single-timestamp value spread, per-device frequency, and the transactional delete. Constructor-injected with only IDbContextFactory<LoggingContext> + IAppLogger, so it's unit-testable with no WPF/OxyPlot-engine dependency — the SessionSampleWriter playbook applied to the read side.
  • DisplayLoggingSession becomes a thin orchestrator that builds the plot series/legend around the points the repository returns; AddChannelSeries no longer seeds the point dictionary (the repository owns that).
  • The internal static test seams (DeduplicateChannelInfo, LoadSingleTickValueSpread) move with the read path; their System.ArgumentException: An item with the same key has already been added. Key: (9090684023231015079, AI0) #572 regression tests are renamed and repointed.

Bug fix — delete failure undetected

SessionDataRepository.DeleteSession now logs and rethrows on failure instead of swallowing. Previously DeleteLoggingSession logged-and-swallowed, so LoggingSessionListViewModel removed the bound row even when the SQL delete failed — the row vanished from the UI while its data remained, reappearing on the next reload. With the rethrow, the view model's existing delete gating keeps the row when the delete actually fails.

Tests

Unit (421/421 green):

Integration (FlaUI, run against the attached device — both pass):

  • Existing StartLoggingSession_…RunsStopsAndDeletesSession exercises the delete bug fix end-to-end (DB-level delete proven from the app's log lines).
  • New ViewLoggedSession_LoadsStoredSessionOntoLoggedDataPlot drives the logged-session viewer end-to-end: loads a stored session onto the plot and asserts via a new LoggedSessionStatsText UIA hook that DisplayLoggingSession (→ SessionDataRepository) ran. Because the whole-row "view" trigger is a MouseBinding with no InvokePattern and out-of-process physical clicks are unreliable, the row carries an invisible DisplaySessionButton invoke-seam bound to the same command.

Notes

  • The viewer scenario adds two small UIA affordances to LoggedDataPanePrototype.xaml (an invisible read hook + an invisible invoke seam), both invisible/non-interactive and documented inline, following the existing PlotStatsText pattern.
  • CLAUDE.md's OxyPlot/ADR-001 plot-gotchas key files are unchanged — the viewport/plot machinery did not move in this PR.

🤖 Generated with Claude Code

…e failures (#592)

Extract the session read/delete path out of the 1,721-line DatabaseLogger god
class into a testable SessionDataRepository (issue #592), and fix the latent
data-integrity bug the extraction unblocks.

Extraction (behavior-preserving):
- SessionDataRepository owns the EF/ADO read path: channel discovery + the fast
  initial batch (LoadInitialSession), the full-range sampled load
  (LoadSampledData), the single-timestamp value spread, per-device frequency,
  and the transactional delete. Constructor-injected with only
  IDbContextFactory<LoggingContext> + IAppLogger, so it is unit-testable with no
  WPF/OxyPlot-engine dependency (the SessionSampleWriter playbook applied to the
  read side).
- DatabaseLogger.DisplayLoggingSession becomes a thin orchestrator that builds
  the plot series/legend around the points the repository returns; the moved
  methods become repository calls. DatabaseLogger drops from 1,721 to 1,376
  lines. AddChannelSeries no longer seeds the point dictionary (the repository
  owns that now).
- The internal-static test seams (DeduplicateChannelInfo,
  LoadSingleTickValueSpread) move with the read path; their #572 regression
  tests are renamed and repointed to SessionDataRepository.

Bug fix ("delete failure undetected"):
- SessionDataRepository.DeleteSession now logs AND rethrows on failure instead
  of swallowing the exception. Previously DatabaseLogger.DeleteLoggingSession
  logged-and-swallowed, so LoggingSessionListViewModel removed the bound row
  even when the SQL delete failed: the row vanished from the UI while its data
  remained, reappearing on the next reload. With the rethrow, the view model's
  existing delete gating keeps the row when the delete actually fails.

Tests:
- New SessionDataRepositoryTests (real temp-SQLite) cover discovery, initial
  batch, sampled load, single-timestamp null, per-device frequency, full delete,
  and the delete-failure-rethrows guard. Existing #572 regression tests
  moved/renamed. Unit gate: 421/421 green.
- New FlaUI scenario ViewLoggedSession_LoadsStoredSessionOntoLoggedDataPlot
  drives the logged-session viewer end-to-end against real hardware: it loads a
  stored session onto the plot (via an invisible DisplaySessionButton invoke
  seam, since the user-facing whole-row trigger is a MouseBinding with no
  InvokePattern and out-of-process physical clicks are unreliable) and asserts
  via a new LoggedSessionStatsText UIA hook that DisplayLoggingSession ran. This
  viewer scenario and the existing delete scenario (which exercises the bug fix)
  both pass on the attached device.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tylerkron tylerkron requested a review from a team as a code owner June 18, 2026 15:48
@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Extract SessionDataRepository and propagate session delete failures
🐞 Bug fix ✨ Enhancement 🧪 Tests 🕐 40+ Minutes

Grey Divider

Description

• Extract session read/delete queries from DatabaseLogger into a testable SessionDataRepository.
• Rethrow failed session deletes so the UI keeps rows when DB deletion fails.
• Add unit + FlaUI coverage and UIA seams to validate logged-session viewing end-to-end.
Diagram

graph TD
  utests["FlaUI UI tests"] --> ui["Logged Data pane (XAML)"] --> vm["Session list VM"] --> dbl["DatabaseLogger"] --> repo["SessionDataRepository"] --> db[("Logging DB (SQLite)")]
  unit["Repository unit tests"] --> repo --> applog["IAppLogger"]
  subgraph Legend
    direction LR
    _t["Test"] ~~~ _ui["UI"] ~~~ _m["Module"] ~~~ _svc["Service"] ~~~ _db[("Database")] 
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Keep delete swallowing; add explicit DB verification before UI removal
  • ➕ No behavioral change in DatabaseLogger exception propagation semantics
  • ➕ Could keep existing callers insulated from transient DB failures
  • ➖ Adds extra DB round-trips and still risks race conditions
  • ➖ More complex than leveraging existing view-model gating via exceptions
  • ➖ Does not improve testability/structure of the read path
2. Use EF-based cascading deletes instead of raw SQL commands
  • ➕ More idiomatic EF; potentially less manual SQL/transaction code
  • ➕ Centralizes delete rules via model configuration
  • ➖ Requires careful cascade configuration across Samples/Metadata/Sessions
  • ➖ May be riskier/more invasive to existing schema and performance expectations
  • ➖ Harder to ensure identical transactional behavior and logging timing

Recommendation: The chosen approach (extracting SessionDataRepository and rethrowing on delete failure) is the best tradeoff: it isolates DB concerns behind a testable component, preserves the high-performance read strategy, and fixes the UI/data-integrity mismatch by letting the existing view-model delete gating actually take effect. Alternatives either add complexity (post-delete verification) or introduce broader EF/schema risk (cascade deletes).

Files changed (10) +1141 / -423

Bug fix (1) +482 / -0
SessionDataRepository.csAdd SessionDataRepository to own session read paths and transactional delete +482/-0

Add SessionDataRepository to own session read paths and transactional delete

• Creates a repository encapsulating channel discovery + initial batch, full-range sampled loading via index seeks, single-timestamp value spread aggregation, per-device frequency reads, and transactional delete. Fixes the latent delete-integrity bug by logging and rethrowing delete failures (instead of swallowing), enabling callers to keep UI rows when data still exists.

Daqifi.Desktop/Loggers/SessionDataRepository.cs

Refactor (1) +50 / -395
DatabaseLogger.csDelegate session reads/deletes to SessionDataRepository and slim DisplayLoggingSession +50/-395

Delegate session reads/deletes to SessionDataRepository and slim DisplayLoggingSession

• Introduces a SessionDataRepository field and routes channel discovery, initial batch loading, sampled-load phase 2, device frequency reads, single-tick spread, and deletes through the repository. Removes inlined EF/ADO session read helpers and the swallow-on-delete-failure behavior; adjusts series creation so repository owns point-dictionary seeding and DatabaseLogger focuses on plotting/legend orchestration.

Daqifi.Desktop/Loggers/DatabaseLogger.cs

Tests (5) +551 / -18
SessionDataRepositoryChannelDiscoveryTests.csRename #572 channel-discovery regression tests to target SessionDataRepository +10/-9

Rename #572 channel-discovery regression tests to target SessionDataRepository

• Renames the test class and redirects calls from DatabaseLogger.DeduplicateChannelInfo to SessionDataRepository.DeduplicateChannelInfo. Updates comments to reflect the new ownership of de-duplication logic and aligns the test narrative with the repository’s initial-load seeding behavior.

Daqifi.Desktop.Test/Loggers/SessionDataRepositoryChannelDiscoveryTests.cs

SessionDataRepositorySingleTickSpreadTests.csMove single-tick value-spread regression tests to SessionDataRepository +6/-5

Move single-tick value-spread regression tests to SessionDataRepository

• Renames the test class and redirects calls from DatabaseLogger.LoadSingleTickValueSpread to SessionDataRepository.LoadSingleTickValueSpread. Updates documentation to reflect that the aggregation now lives in the extracted repository.

Daqifi.Desktop.Test/Loggers/SessionDataRepositorySingleTickSpreadTests.cs

SessionDataRepositoryTests.csAdd SQLite-backed unit tests for SessionDataRepository read/delete contract +361/-0

Add SQLite-backed unit tests for SessionDataRepository read/delete contract

• Introduces a comprehensive behavior-contract suite that runs against a real temp SQLite DB via an IDbContextFactory. Covers initial discovery/batch load, full-range sampled load behavior, single-timestamp handling, per-device frequency metadata reads, transactional delete, and the delete-failure-rethrows guard via an injected throwing factory.

Daqifi.Desktop.Test/Loggers/SessionDataRepositoryTests.cs

DaqifiAppFixture.csAdd UI-test helpers to display newest logged session and read viewer stats hook +93/-0

Add UI-test helpers to display newest logged session and read viewer stats hook

• Adds constants for the new LoggedSessionStatsText and DisplaySessionButton UIA elements. Introduces DisplayNewestLoggedSession() (invoke seam) and WaitForDisplayedSessionSampleCount() (polling read hook) to reliably drive and assert the logged-session viewer flow despite WPF MouseBinding limitations and async loading.

Daqifi.Desktop.UITest/DaqifiAppFixture.cs

LoggingSessionTests.csAdd end-to-end test for viewing a stored logged session on the plot +81/-4

Add end-to-end test for viewing a stored logged session on the plot

• Updates delete assertions commentary to reflect propagated delete failures after the extraction. Adds ViewLoggedSession_LoadsStoredSessionOntoLoggedDataPlot, which creates a session, loads it via the invoke seam, asserts a non-zero displayed sample count via LoggedSessionStatsText, and verifies the app didn’t log DisplayLoggingSession failures; then cleans up by deleting the created session.

Daqifi.Desktop.UITest/LoggingSessionTests.cs

Documentation (2) +11 / -10
README.mdDocument new logged-session viewer scenario and updated delete semantics +6/-4

Document new logged-session viewer scenario and updated delete semantics

• Adds the new viewer workflow to the UITest scenario table and explains the UIA seams used to invoke and verify viewing a stored session. Updates gotcha text to reflect that delete failures now rethrow, while keeping log-based DB confirmation as an independent assertion.

Daqifi.Desktop.UITest/README.md

LoggingSessionListViewModel.csUpdate delete-path comments to reflect propagated delete failures after extraction +5/-6

Update delete-path comments to reflect propagated delete failures after extraction

• Updates explanatory comments around delete gating to reflect that DatabaseLogger.DeleteLoggingSession now rethrows on failure (via SessionDataRepository), making the view-model catch path active and preventing silent UI row removal when DB deletion fails.

Daqifi.Desktop/ViewModels/LoggingSessionListViewModel.cs

Other (1) +47 / -0
LoggedDataPanePrototype.xamlAdd invisible UIA hooks for logged-session viewer (stats read + invoke seam) +47/-0

Add invisible UIA hooks for logged-session viewer (stats read + invoke seam)

• Adds an always-present, invisible TextBlock exposing CurrentSessionSampleCount via AutomationProperties.Name for black-box proof that a session was loaded onto the plot. Adds an invisible per-row Button bound to the same DisplayLoggingSessionCommand to provide an InvokePattern seam for reliable out-of-process UI automation.

Daqifi.Desktop/View/Prototype/LoggedDataPanePrototype.xaml

@qodo-code-review

qodo-code-review Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📎 Requirement gaps (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 48 rules

Grey Divider


Remediation recommended

1. Mutable empty singleton ✓ Resolved 🐞 Bug ☼ Reliability
Description
InitialSessionLoad.Empty is a static singleton that includes a mutable Points dictionary, so any
accidental mutation of the returned empty result will persist across all future empty-session loads.
This can lead to hard-to-diagnose state leakage between calls/tests and should be replaced with a
fresh (or immutable) empty result.
Code

Daqifi.Desktop/Loggers/SessionDataRepository.cs[R28-39]

+internal sealed record InitialSessionLoad(
+    IReadOnlyList<SessionChannelInfo> Channels,
+    Dictionary<(string deviceSerial, string channelName), List<DataPoint>> Points,
+    DateTime? FirstTime,
+    int TotalSampleCount)
+{
+    /// <summary>True when the session had no samples to discover channels from.</summary>
+    public bool IsEmpty => Channels.Count == 0;
+
+    /// <summary>The empty-session result: no channels, no points, no time origin.</summary>
+    public static InitialSessionLoad Empty { get; } = new([], new(), null, 0);
+}
Evidence
The empty-session sentinel is implemented as a static property initialized once with new() for
Points, and Points is a mutable Dictionary<...> exposed to callers via the record’s public
property; this creates shared mutable state across calls.

Daqifi.Desktop/Loggers/SessionDataRepository.cs[28-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`InitialSessionLoad.Empty` is a static singleton initialized once with a mutable `Dictionary` for `Points`. Because the instance is reused, any mutation of `Empty.Points` (even accidental) will affect all later callers.

### Issue Context
This is a robustness/API-safety issue: the empty result is intended as a sentinel, but it currently carries shared mutable state.

### Fix Focus Areas
- Make the empty result non-singleton (return a new instance each time), or make `Points` immutable/read-only.
- If keeping a static `Empty`, ensure it contains only immutable state (e.g., `IReadOnlyDictionary` backed by an immutable dictionary).

- Daqifi.Desktop/Loggers/SessionDataRepository.cs[28-39]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Empty catch in TestCleanup 📘 Rule violation ◔ Observability
Description
SessionDataRepositoryTests.TestCleanup introduces a bare catch that swallows exceptions without
any logging or contextual details, reducing diagnosability when cleanup fails. This violates the
requirement to log caught exceptions with operation context.
Code

Daqifi.Desktop.Test/Loggers/SessionDataRepositoryTests.cs[R39-46]

+                try
+                {
+                    if (File.Exists(path + suffix)) { File.Delete(path + suffix); }
+                }
+                catch
+                {
+                    // Best-effort cleanup.
+                }
Evidence
PR Compliance ID 244826 requires logging caught exceptions with contextual operation details. The
added catch block in SessionDataRepositoryTests.TestCleanup is empty aside from a comment, so
exceptions during file deletion are swallowed without any log entry or context.

Rule 244826: Log caught exceptions with contextual operation details
Daqifi.Desktop.Test/Loggers/SessionDataRepositoryTests.cs[39-46]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new bare `catch` in `SessionDataRepositoryTests.TestCleanup` swallows exceptions without logging/context, which violates the requirement to log caught exceptions.

## Issue Context
This occurs during best-effort temp SQLite file cleanup; exceptions should be logged (with non-sensitive context like the file path being deleted) or the catch should be narrowed to expected exception types.

## Fix Focus Areas
- Daqifi.Desktop.Test/Loggers/SessionDataRepositoryTests.cs[39-46]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Qodo review (#607): the empty-session sentinel was a cached static singleton
carrying a mutable Points dictionary, so any accidental mutation of the empty
result would leak into every later empty-session load. Return a new instance on
each access instead. Today's empty path never mutates Points, but this removes
the latent shared-mutable-state footgun.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tylerkron

Copy link
Copy Markdown
Contributor Author

Thanks @qodo-code-review — went through both findings:

2. Mutable empty singleton (InitialSessionLoad.Empty) — fixed in 8b79c84. Good catch on the latent footgun: the sentinel was a cached static instance carrying a mutable Points dictionary. It's now a computed property returning a fresh new([], new(), null, 0) on each access, so the empty result can never share mutable state across loads. (Today's empty path returns before touching Points, but the fix removes the trap for future callers.) The 18 SessionDataRepository unit tests stay green.

1. Empty catch in SessionDataRepositoryTests.TestCleanup — keeping as-is. This is best-effort temp-SQLite file teardown in a [TestCleanup], and it's intentionally identical to the established convention in the sibling test files — SessionSampleWriterTests.TestCleanup and the TempSqliteLoggingContextFactory.Dispose in SessionDataRepositorySingleTickSpreadTests both use the same catch { /* Best-effort cleanup. */ }. If File.Delete throws (the file is still locked), there's nothing actionable in teardown and the OS reclaims the temp directory; the test's real assertions have already run. These tests have no IAppLogger, so satisfying rule 244826 here would mean adding test-only console/diagnostic logging that diverges from every neighboring cleanup. If the team wants that rule enforced for test teardown, it'd be better as a separate repo-wide sweep across all these _tempDbPaths cleanups so they stay consistent, rather than diverging this one file.

@qodo-code-review

Copy link
Copy Markdown
Contributor

Thanks @qodo-code-review — went through both findings:

2. Mutable empty singleton (InitialSessionLoad.Empty) — fixed in 8b79c84. Good catch on the latent footgun: the sentinel was a cached static instance carrying a mutable Points dictionary. It's now a computed property returning a fresh new([], new(), null, 0) on each access, so the empty result can never share mutable state across loads. (Today's empty path returns before touching Points, but the fix removes the trap for future callers.) The 18 SessionDataRepository unit tests stay green.

1. Empty catch in SessionDataRepositoryTests.TestCleanup — keeping as-is. This is best-effort temp-SQLite file teardown in a [TestCleanup], and it's intentionally identical to the established convention in the sibling test files — SessionSampleWriterTests.TestCleanup and the TempSqliteLoggingContextFactory.Dispose in SessionDataRepositorySingleTickSpreadTests both use the same catch { /* Best-effort cleanup. */ }. If File.Delete throws (the file is still locked), there's nothing actionable in teardown and the OS reclaims the temp directory; the test's real assertions have already run. These tests have no IAppLogger, so satisfying rule 244826 here would mean adding test-only console/diagnostic logging that diverges from every neighboring cleanup. If the team wants that rule enforced for test teardown, it'd be better as a separate repo-wide sweep across all these _tempDbPaths cleanups so they stay consistent, rather than diverging this one file.

That rationale makes sense.

  • finding 2: for best-effort [TestCleanup] teardown, swallowing File.Delete failures is defensible when there’s no actionable recovery.
  • Keeping it consistent with the sibling temp-SQLite cleanup paths also avoids introducing one-off test-only logging.

So I’m fine with leaving SessionDataRepositoryTests.TestCleanup as-is.

@github-actions

Copy link
Copy Markdown

📊 Code Coverage Report

Summary

Summary
Generated on: 6/18/2026 - 4:53:03 PM
Coverage date: 6/18/2026 - 4:51:40 PM - 6/18/2026 - 4:52:56 PM
Parser: MultiReport (5x Cobertura)
Assemblies: 3
Classes: 131
Files: 158
Line coverage: 39.5% (3552 of 8974)
Covered lines: 3552
Uncovered lines: 5422
Coverable lines: 8974
Total lines: 29032
Branch coverage: 28.7% (861 of 2994)
Covered branches: 861
Total branches: 2994
Method coverage: Feature is only available for sponsors

Coverage

DAQiFi - 39.5%
Name Line Branch
DAQiFi 39.5% 28.8%
Daqifi.Desktop.App 3.7% 0%
Daqifi.Desktop.Channel.AbstractChannel 66.1% 44.7%
Daqifi.Desktop.Channel.AnalogChannel 58.7% 12.5%
Daqifi.Desktop.Channel.Channel 11.5% 0%
Daqifi.Desktop.Channel.ChannelColorManager 100% 100%
Daqifi.Desktop.Channel.DataSample 91.6%
Daqifi.Desktop.Channel.DigitalChannel 65.2% 12.5%
Daqifi.Desktop.Commands.CompositeCommand 0% 0%
Daqifi.Desktop.Commands.HostCommands 0%
Daqifi.Desktop.Commands.WeakEventHandlerManager 0% 0%
Daqifi.Desktop.Configuration.FirewallConfiguration 90.6% 66.6%
Daqifi.Desktop.Configuration.WindowsFirewallWrapper 64% 68.4%
Daqifi.Desktop.ConnectionManager 41.8% 39.2%
Daqifi.Desktop.Converters.BoolToActiveStatusConverter 0% 0%
Daqifi.Desktop.Converters.BoolToConnectionStatusConverter 0% 0%
Daqifi.Desktop.Converters.BoolToStatusColorConverter 0% 0%
Daqifi.Desktop.Converters.BrushColorMatchConverter 0% 0%
Daqifi.Desktop.Converters.ConnectionTypeToColorConverter 0% 0%
Daqifi.Desktop.Converters.ConnectionTypeToUsbConverter 0% 0%
Daqifi.Desktop.Converters.InvertedBoolToVisibilityConverter 0% 0%
Daqifi.Desktop.Converters.ListToStringConverter 0% 0%
Daqifi.Desktop.Converters.NotNullToVisibilityConverter 0% 0%
Daqifi.Desktop.Converters.OxyColorToBrushConverter 0% 0%
Daqifi.Desktop.Device.AbstractStreamingDevice 61.2% 52.1%
Daqifi.Desktop.Device.DeviceMessage 92.8%
Daqifi.Desktop.Device.Firmware.BootloaderSessionStreamingDeviceAdapter 0% 0%
Daqifi.Desktop.Device.Firmware.FirmwareUpdateCoordinator 65.6% 54.8%
Daqifi.Desktop.Device.Firmware.FirmwareUpdateServiceConfig 100%
Daqifi.Desktop.Device.Firmware.WifiPromptDelayProcessRunner 0% 0%
Daqifi.Desktop.Device.NativeMethods 100%
Daqifi.Desktop.Device.SerialDevice.SerialStreamingDevice 44.6% 33.3%
Daqifi.Desktop.Device.WiFiDevice.DaqifiStreamingDevice 44% 34.3%
Daqifi.Desktop.DialogService.DialogService 0% 0%
Daqifi.Desktop.DialogService.ServiceLocator 0% 0%
Daqifi.Desktop.DiskSpace.DiskSpaceCheckResult 100%
Daqifi.Desktop.DiskSpace.DiskSpaceEventArgs 100%
Daqifi.Desktop.DiskSpace.DiskSpaceMonitor 88.2% 86.6%
Daqifi.Desktop.DuplicateDeviceCheckResult 100%
Daqifi.Desktop.Exporter.LoggingSessionSampleSource 98.7% 77.2%
Daqifi.Desktop.Exporter.OptimizedLoggingSessionExporter 56.9% 46.1%
Daqifi.Desktop.Helpers.BooleanConverter`1 0% 0%
Daqifi.Desktop.Helpers.BooleanToInverseBoolConverter 0% 0%
Daqifi.Desktop.Helpers.BooleanToVisibilityConverter 0%
Daqifi.Desktop.Helpers.EnumDescriptionConverter 100% 100%
Daqifi.Desktop.Helpers.IntToVisibilityConverter 0% 0%
Daqifi.Desktop.Helpers.MinMaxDownsampler 100% 96.4%
Daqifi.Desktop.Helpers.MyMultiValueConverter 0%
Daqifi.Desktop.Helpers.NaturalSortHelper 100% 100%
Daqifi.Desktop.Helpers.OxyPlotDarkTheme 0%
Daqifi.Desktop.Helpers.VersionHelper 98.2% 66.2%
Daqifi.Desktop.Logger.DatabaseLogger 0% 0%
Daqifi.Desktop.Logger.DatabaseMigrator 0% 0%
Daqifi.Desktop.Logger.DeviceLegendGroup 100% 100%
Daqifi.Desktop.Logger.InitialSessionLoad 100%
Daqifi.Desktop.Logger.LoggedSeriesLegendItem 0% 0%
Daqifi.Desktop.Logger.LoggingContext 100%
Daqifi.Desktop.Logger.LoggingContextDesignTimeFactory 0%
Daqifi.Desktop.Logger.LoggingManager 0% 0%
Daqifi.Desktop.Logger.LoggingSession 36.5% 10.8%
Daqifi.Desktop.Logger.PlotLogger 14% 38.7%
Daqifi.Desktop.Logger.SessionChannelInfo 100%
Daqifi.Desktop.Logger.SessionDataRepository 97.9% 91.3%
Daqifi.Desktop.Logger.SessionDeviceMetadata 80%
Daqifi.Desktop.Logger.SessionSampleWriter 96% 91.3%
Daqifi.Desktop.Logger.SummaryLogger 0% 0%
Daqifi.Desktop.Logger.TimestampGapDetector 95% 83.3%
Daqifi.Desktop.Loggers.ImportOptions 66.6%
Daqifi.Desktop.Loggers.ImportProgress 0% 0%
Daqifi.Desktop.Loggers.ImportTimestampQuality 100% 100%
Daqifi.Desktop.Loggers.SdCardImportResult 100%
Daqifi.Desktop.Loggers.SdCardSessionImporter 49.7% 51%
Daqifi.Desktop.MainWindow 0% 0%
Daqifi.Desktop.Migrations.AddSamplesSessionTimeIndex 97.8%
Daqifi.Desktop.Migrations.AddSessionDeviceMetadata 98.6%
Daqifi.Desktop.Migrations.AddSessionSampleCount 98.1%
Daqifi.Desktop.Migrations.InitialSQLiteMigration 97.4%
Daqifi.Desktop.Migrations.LoggingContextModelSnapshot 0%
Daqifi.Desktop.Models.AddProfileModel 0%
Daqifi.Desktop.Models.DaqifiSettings 83.3% 100%
Daqifi.Desktop.Models.DebugDataCollection 6.6% 0%
Daqifi.Desktop.Models.DebugDataModel 0% 0%
Daqifi.Desktop.Models.Notifications 75%
Daqifi.Desktop.Models.SdCardFile 16.6% 0%
Daqifi.Desktop.Services.NoOpMessageBoxService 0%
Daqifi.Desktop.Services.WindowsPrincipalAdminChecker 0%
Daqifi.Desktop.Services.WpfMessageBoxService 0%
Daqifi.Desktop.UpdateVersion.VersionNotification 85.7% 54.1%
Daqifi.Desktop.View.ConnectionDialog 0% 0%
Daqifi.Desktop.View.DebugWindow 0% 0%
Daqifi.Desktop.View.DeviceLogsView 0% 0%
Daqifi.Desktop.View.DuplicateDeviceDialog 0% 0%
Daqifi.Desktop.View.ErrorDialog 0% 0%
Daqifi.Desktop.View.ExportDialog 0% 0%
Daqifi.Desktop.View.FirmwareDialog 0% 0%
Daqifi.Desktop.View.Flyouts.FirmwareFlyout 0% 0%
Daqifi.Desktop.View.Flyouts.LiveGraphFlyout 0% 0%
Daqifi.Desktop.View.Flyouts.NotificationsFlyout 0% 0%
Daqifi.Desktop.View.Flyouts.SummaryFlyout 0% 0%
Daqifi.Desktop.View.MigrationStatusWindow 0% 0%
Daqifi.Desktop.View.MinimapInteractionController 0% 0%
Daqifi.Desktop.View.ProfilesPane 0% 0%
Daqifi.Desktop.View.Prototype.ChannelsPanePrototype 0% 0%
Daqifi.Desktop.View.Prototype.DevicesPanePrototype 0% 0%
Daqifi.Desktop.View.Prototype.LiveGraphPane 0% 0%
Daqifi.Desktop.View.Prototype.LoggedDataPanePrototype 0% 0%
Daqifi.Desktop.View.SuccessDialog 0% 0%
Daqifi.Desktop.ViewModels.ChannelsPaneViewModel 0% 0%
Daqifi.Desktop.ViewModels.ChannelTileViewModel 0% 0%
Daqifi.Desktop.ViewModels.ConfirmOverlayViewModel 100% 100%
Daqifi.Desktop.ViewModels.ConnectionDialogViewModel 38.9% 38.2%
Daqifi.Desktop.ViewModels.DaqifiViewModel 13.6% 7.5%
Daqifi.Desktop.ViewModels.DeviceLogsViewModel 50.4% 43.3%
Daqifi.Desktop.ViewModels.DevicesPaneViewModel 0% 0%
Daqifi.Desktop.ViewModels.DeviceTileViewModel 0% 0%
Daqifi.Desktop.ViewModels.DuplicateDeviceDialogViewModel 0%
Daqifi.Desktop.ViewModels.ErrorDialogViewModel 0%
Daqifi.Desktop.ViewModels.ExportDialogViewModel 59.4% 33.3%
Daqifi.Desktop.ViewModels.FirmwareDialogViewModel 0% 0%
Daqifi.Desktop.ViewModels.LoggingSessionListViewModel 95.4% 88.2%
Daqifi.Desktop.ViewModels.NewProfileChannelItem 0%
Daqifi.Desktop.ViewModels.NewProfileDeviceItem 0% 0%
Daqifi.Desktop.ViewModels.ProfilesPaneViewModel 0% 0%
Daqifi.Desktop.ViewModels.SettingsViewModel 0% 0%
Daqifi.Desktop.ViewModels.SuccessDialogViewModel 0%
Daqifi.Desktop.WindowViewModelMapping.IWindowViewModelMappingsContract 0%
Daqifi.Desktop.WindowViewModelMapping.WindowViewModelMappings 0%
Sentry.Generated.BuildPropertyInitializer 100%
Daqifi.Desktop.Common - 40.5%
Name Line Branch
Daqifi.Desktop.Common 40.5% 23.8%
Daqifi.Desktop.Common.AppDataPaths 84.2% 50%
Daqifi.Desktop.Common.Loggers.AppLogger 35.2% 21%
Daqifi.Desktop.Common.Loggers.NoOpLogger 0%
Daqifi.Desktop.IO - 100%
Name Line Branch
Daqifi.Desktop.IO 100% ****
Daqifi.Desktop.IO.Messages.MessageEventArgs`1 100%

Coverage report generated by ReportGeneratorView full report in build artifacts

@tylerkron tylerkron merged commit a2d1f71 into main Jun 18, 2026
2 checks passed
@tylerkron tylerkron deleted the fix/extract-session-data-repository branch June 18, 2026 16:56
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