Skip to content

[pull] main from erikdarlingdata:main#3

Merged
pull[bot] merged 213 commits into
ehtick:mainfrom
erikdarlingdata:main
Mar 12, 2026
Merged

[pull] main from erikdarlingdata:main#3
pull[bot] merged 213 commits into
ehtick:mainfrom
erikdarlingdata:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Mar 12, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

HannahVernon and others added 30 commits February 27, 2026 14:26
…_DIAGNOSTIC wait types, and WAITFOR wait types.
…to allow future configurability on the number of long-running queries returned. Added optional parameter to control display of WAITFOR types in future.
…clusions

Feature/long running query exclusions
…c() method. Removed System.Collections.Generic using statement as it is unnecessary.
…KUPTHREAD-to-long-running-queries

Added exclusion for backup-related waits to GetLongRunningQueriesAsync() method.
…dded miscWaitsFilter to exclude XE_LIVE_TARGET_TVF waits. Removed unused parameters. Corrected minimum value for maxLongRunningQueryCount (minimum 1 instead of 5).
…KUPTHREAD-to-long-running-queries

Feature/add exclusion for backupthread to long running queries
…ITFOR, BACKUPTHREAD, BACKUPIO, and XE_LIVE_TARGET_TVF wait types in Lite/Services/LocalDataService.WaitStats.cs
…ries-monitor-changes-to-lite

Added filtering for various wait types to long running query code in Lite.
Adds LongRunningQueryMaxResults to UserPreferences (default 5) and
exposes it in the Settings UI alongside the existing duration threshold.
Threads the value through GetAlertHealthAsync and GetLongRunningQueriesAsync
to replace the hardcoded TOP(5) in the DMV query.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds Math.Clamp(1, int.MaxValue) guard to GetLongRunningQueriesAsync in
both Dashboard and Lite, and updates the Dashboard settings validation
to use an explicit range check with a descriptive error message.

Mirrors the LongRunningQueryMaxResults setting across the Lite project:
adds the App property, loads/saves it to settings.json, exposes it in
the Lite Settings UI, and passes it through to GetLongRunningQueriesAsync
to replace the hardcoded LIMIT 5.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevents an OverflowException if the value in settings.json is outside
the int32 range. The value is read as long, clamped to [1, int.MaxValue],
then cast back to int.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces hardcoded wait type exclusions in GetLongRunningQueriesAsync
with user-configurable booleans for SP_SERVER_DIAGNOSTICS, WAITFOR /
BROKER_RECEIVE_WAITFOR, backup waits, and miscellaneous waits. All
four filters default to true (existing behavior preserved). Settings
are exposed in the Notifications section of both Dashboard and Lite
Settings UIs and persisted to UserPreferences / settings.json.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…config-settings

Feature/long running queries config settings
…config-settings

Feature/long running queries config settings
Users can now exclude specific databases (e.g. DBAtools, msdb) from
generating alerts. The exclusion list is a comma-separated text box in
Settings > Notifications for both projects.

- Dashboard: filters LRQ at trigger level, blocking via SQL NOT IN clause,
  deadlock context filtered before email is built; list persisted in UserPreferences
- Lite: filters LRQ at trigger level; list persisted to alert_excluded_databases
  JSON array in settings.json

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
#414)

The GUI installer read from installation_history for version detection but
never wrote to it, causing subsequent upgrades to fail to detect the prior
install. Adds LogInstallationHistoryAsync mirroring the CLI installer's
existing LogInstallationHistory method.

Fixes #409

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Added exclusions in GetLongRunningQueriesAsync() method for SP_SERVER_DIAGNOSTIC wait types, and WAITFOR wait types.

* Added TOP parameter for query in GetLongRunningQueriesAsync() method to allow future configurability on the number of long-running queries returned.  Added optional parameter to control display of WAITFOR types in future.

* Replaced waitForFilter string constructor with C# string interpolation instead of janky string addition.

* Added exclusion for backup-related waits to GetLongRunningQueriesAsync() method.  Removed System.Collections.Generic using statement as it is unnecessary.

* Reverted Controls/LandingPage.xaml.cs

* Added BROKER_RECEIVE_WAITFOR wait type to waitforFilter exclusions.  Added miscWaitsFilter to exclude XE_LIVE_TARGET_TVF waits.  Removed unused parameters.  Corrected minimum value for maxLongRunningQueryCount (minimum 1 instead of 5).

* Added filtering for SP_SERVER_DIAGNOSTICS, WAITFOR, BROKER_RECEIVE_WAITFOR, BACKUPTHREAD, BACKUPIO, and XE_LIVE_TARGET_TVF wait types in Lite/Services/LocalDataService.WaitStats.cs

* Add configurable max results setting for long-running queries

Adds LongRunningQueryMaxResults to UserPreferences (default 5) and
exposes it in the Settings UI alongside the existing duration threshold.
Threads the value through GetAlertHealthAsync and GetLongRunningQueriesAsync
to replace the hardcoded TOP(5) in the DMV query.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Apply max results validation and Lite parity for long-running queries

Adds Math.Clamp(1, int.MaxValue) guard to GetLongRunningQueriesAsync in
both Dashboard and Lite, and updates the Dashboard settings validation
to use an explicit range check with a descriptive error message.

Mirrors the LongRunningQueryMaxResults setting across the Lite project:
adds the App property, loads/saves it to settings.json, exposes it in
the Lite Settings UI, and passes it through to GetLongRunningQueriesAsync
to replace the hardcoded LIMIT 5.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Use GetInt64() when loading long-running query max results from JSON

Prevents an OverflowException if the value in settings.json is outside
the int32 range. The value is read as long, clamped to [1, int.MaxValue],
then cast back to int.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add configurable long-running query filter toggles

Replaces hardcoded wait type exclusions in GetLongRunningQueriesAsync
with user-configurable booleans for SP_SERVER_DIAGNOSTICS, WAITFOR /
BROKER_RECEIVE_WAITFOR, backup waits, and miscellaneous waits. All
four filters default to true (existing behavior preserved). Settings
are exposed in the Notifications section of both Dashboard and Lite
Settings UIs and persisted to UserPreferences / settings.json.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* merged with incoming dev branch

* Parameterized TOP/LIMIT value in Dashboard/Services/DatabaseService.NocHealth.cs and Lite/Services/LocalDataService.WaitStats.cs, and clamped the upper bound of the value to 1000 to avoid foot shooting.  Removed blank lines as per Erik's request.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…ail (#416)

- Spool operators now show Eager/Lazy prefix (e.g., "Eager Index Spool"
  instead of just "Index Spool") by prepending from LogicalOp
- PlanIconMapper entries added for all Eager/Lazy spool variants
- UnmatchedIndexes warning now parses child Parameterization elements
  to show specific database.schema.table.index names

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
… time instead of at runtime: warning CA1847: Use 'string.Contains(char)' instead of 'string.Contains(string)' when searching for a single character (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1847) warning CA1875: Use 'Regex.Count' instead of 'Regex.Matches(...).Count' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1875) warning CA1863: Cache a 'CompositeFormat' for repeated use in this formatting operation (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1863) (#346)

Co-authored-by: Orestes Zoupanos <orestes.zoupanos@tpr.gov.uk>
PR #346 left Lite PlanAnalyzer with 3 old-style regex fields and inline
Regex.IsMatch calls, and added unnecessary RegexOptions.Compiled to all
GeneratedRegex attributes (source generator always compiles, flag is ignored).

- Convert remaining Lite regex fields to use GeneratedRegex source generator
- Convert all inline Regex.IsMatch calls to GeneratedRegex in both apps
- Remove RegexOptions.Compiled from all [GeneratedRegex] attributes
- Keep both PlanAnalyzer copies in sync with identical regex methods

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Documents required permissions for all platforms: on-prem Full/Lite,
Azure SQL Database (contained user), Azure SQL MI, and AWS RDS.
Includes copy-paste SQL scripts. Updates comparison table and
troubleshooting to link to the new section.

Prompted by user question in issue #418.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
HannahVernon and others added 27 commits March 10, 2026 21:00
…ntion

DuckDB 1.5.0: non-blocking checkpointing, free block reuse, 17% throughput
improvement. Storage format v67→v68 upgrades transparently on first open.

ArchiveService: compact per-cycle parquet files into monthly files
(YYYYMM_tablename.parquet) after each archive cycle. Strips dead
query_plan_text column from query_store_stats during compaction. Uses
in-memory DuckDB connection — no contention with collectors. Reduces
steady-state archive from thousands of files to ~75 (25 tables × 3 months).

RetentionService: switch from 90-day file deletion to 3-month monthly
file deletion. Recognizes all naming formats (YYYYMM_, YYYYMMDD_, YYYY-MM_).

Benchmarked: v_wait_stats query dropped from 1.7s to 0.03s after compaction.
Lite refresh stable at 1.3-1.5s (down from 6-13s pre-optimization).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ction

Upgrade DuckDB to 1.5.0 + automatic parquet compaction
GetDatabaseSizeMb() reports file size on disk, which stays frozen when
DuckDB 1.5.0 reuses free blocks. New GetUsedDataSizeMb() queries
pragma_database_size() for actual used blocks. Status bar now shows
"Database: 175.5 / 423.8 MB" (used / file).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tus-bar

Show used vs file size in Lite status bar
Splits the DuckDB write stopwatch into three components (SqlDataReader,
appender, flush) and logs a warning when total exceeds 2 seconds. This
identified SQL Server Query Store DMV contention as the root cause of
collector spikes during heavy analytical workloads — not DuckDB writes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…agnostic

Add Query Store collector spike diagnostic timing
Add missing changelog entries for PRs #503-#518: DuckDB 1.5.0 upgrade,
parquet compaction (13-26x perf improvement), SignPath code signing,
ReadOnlyIntent, status bar used/file size, collector diagnostics,
plan viewer fixes. Update README with code signing note, DuckDB 1.5.0
data storage section, ReadOnlyIntent quick start, expanded FinOps
description. Release date set to 2026-03-11.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
….2.0

Update changelog and README for v2.2.0
WPF does not support DynamicResource on Freezable properties like
SolidColorBrush.Color. Changed to StaticResource in both editions'
AlertDetailWindow.xaml to avoid potential runtime crash.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Click handler fires before WPF binding updates rule.Enabled, so
SetRuleEnabled was persisting the pre-toggle value. Read cb.IsChecked
directly instead of rule.Enabled in both editions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replaced raw SQL against config_alert_log with a call to
dataService.GetAlertHistoryAsync(), which queries v_config_alert_log
(includes archived parquet data) and filters out dismissed alerts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The get_alert_settings MCP tool takes UserPreferencesService via DI,
but it was never registered in McpHostService, causing
InvalidOperationException when called. Added it to the constructor
and DI registration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… lock, CPU detailText, mute-all guard, purge ordering, null checks, JSON alignment

5. MuteRuleDialog now clones the rule before editing (both editions)
6. Mute Similar uses AlertMuteContext constructor (both editions)
7. AddRuleAsync skips memory-add on persist failure (Lite)
8. LogAlertAsync acquires write lock before INSERT (Lite)
9. CPU alert now passes detailText to TrySendAlertEmailAsync (Lite)
10. Save_Click warns when all filter fields are null (both editions)
11. PurgeExpiredRulesAsync deletes from DB before memory (Lite)
12. Null checks on ContextMenu cast in AlertsHistoryContent (Dashboard)
13. Aligned get_alert_settings JSON field names across editions (Lite)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1. EmailAlertService.LogAlertAsync: acquire write lock BEFORE creating
   connection, matching the pattern used throughout the codebase.
2. Dashboard CPU alert: pass detailText to RecordAlert so the alert
   detail window shows CPU percentage and threshold.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When the same server was added twice with different ApplicationIntent
(primary vs read-only replica), both produced identical server_id
hashes because GetServerId() only hashed ServerName. All collected
data merged under one ID, making charts identical for both tabs.

Fix: GetServerNameForStorage() appends ":RO" to the server name when
ReadOnlyIntent is true, producing a unique server_id and distinct
server_name in DuckDB. Non-RO servers are unchanged (no migration).

Also adds "(Read-Only)" indicators throughout the UI: sidebar, tab
headers, status bar, alerts, tray notifications, overview cards,
Manage Servers grid, and MCP tool responses. Status bar now updates
on tab switch to reflect the active server.

Tested with Azure SQL DB Business Critical readable replica.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Feature/alert muting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
upload-artifact@v4 wraps files in its own container, causing a
zip-within-a-zip when we upload pre-zipped archives. SignPath then
can't find the exe inside the nested structure. Fix: upload the
publish directory contents directly. Re-zip from signed output
for the release assets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…load

Fix SignPath signing: upload directories instead of zips
v2.2.0: Fix SignPath signing
@pull pull Bot locked and limited conversation to collaborators Mar 12, 2026
@pull pull Bot added the ⤵️ pull label Mar 12, 2026
@pull pull Bot merged commit 8ed7a95 into ehtick:main Mar 12, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants