Repository navigation
Plan viewer: add a Server Context card to the Plan Insights strip (#4597) - #4614
Merged
Merged
Conversation
Ports PerformanceStudio's AnalyzerConfig/RulesConfig (disabled rules, severity overrides) and the top-level ServerMetadata fields into PerformanceMonitor.PlanAnalysis, adds PlanWarning.RuleNumber, and adds Analyze/Run overloads that take (config, serverMetadata, cancellationToken) and thread both down to the statement and node walks. The existing overloads still forward to AnalyzerConfig.Default and a null metadata, and no rule reads either new parameter yet, so analyzer output is unchanged.
…ng framework as legacy (#4566)
…ing (#4535) Ports erikdarlingdata/PerformanceStudio's severity-override pass: overrides now find a warning's rule via PlanWarning.RuleNumber instead of matching WarningType against a rule-to-name table, and the engine's own warnings (Source == SqlServer) are always skipped. Also ports PlanStatements.EnumerateAllWithContainer, with EnumerateAll delegating to it so the plain and container-carrying walks stay one walk.
…5-analyzer-config
…5-analyzer-config
#4535, #4566) The plumbing step's RuleNumber_DefaultsToNull_UntilLaterStepsStampIt pinned the state partway through the per-rule configuration rollout (only rule 3 stamped). Every step that stamps a rule has landed on this branch, so that pin is wrong by design now. Replaces it with PlanSync4535RuleNumberCensusTests: a code census over every new PlanWarning construction in PlanAnalyzer.cs (each must set RuleNumber, except a SqlServer-sourced initializer), a runtime census over the existing plan fixtures (every analyzer finding carries a non-null RuleNumber), and a cross-step check that disabling every stamped rule number leaves zero analyzer findings.
…into plan-sync/4530-entry-points
Ports PerformanceStudio dev's insights-strip card system (erikdarlingdata/PerformanceStudio@87bad14) to the shared plan viewer used by both the Darling Viewer and Lite. All three cards (Runtime Summary, Missing Indexes, Wait Stats) now sit on the same neutral BackgroundLightBrush surface with a 3px per-card accent edge (InsightIndexBrush, InsightWaitsBrush) instead of a full-bleed tinted background. Runtime Summary keeps a blank edge as the neutral centre. A card with nothing to report now goes quiet: its header drops to the muted foreground and its accent edge dims to 0.35, via a shared SetInsightQuiet helper whose quiet/non-quiet values live in the new pure PerformanceMonitor.PlanAnalysis.InsightCardStyle so they are testable outside WPF. No inline hex is left in the insight-card markup or code.
Adds three tests the earlier #4530 steps skipped: - a live Postgres pin that seeds collect.server_properties and collect.server_config on a migrated store and asserts DarlingServerMetadataReader.ReadAsync returns the edition and MAXDOP, then runs the same plan XML through the analysis formatter and confirms rule 38 (Standard Edition DOP 2 limitation) gives its Warning, plus a no-rows case that stays on the Info branch; - a drill-down pin: a PLAN_WARNING finding's drill-down surfaces the rule-38 Warning when PgDrillDownCollector runs against a seeded Standard Edition / MAXDOP 8 server; - a Lite.Tests pin (build-only on macOS) for LocalDataService.GetServerMetadataForPlanAnalysisAsync against a seeded DuckDB fixture, plus a Darling.Tests source-census pin that the Lite reader's SQL names the same view and columns Darling's migrated schema and reader use. Ported the reader's column-name RED by temporarily renaming the FROM clause, confirming the new live pin fails, then reverting.
Ports PerformanceStudio dev's Parameters insight card (erikdarlingdata/PerformanceStudio@85492a1) to the shared plan viewer used by both the Darling Viewer and Lite. The card lists each parameter's name, data type, compiled value and runtime value, tints a runtime value amber when it differs from its compiled value (possible parameter sniffing), and annotates the card when every compiled value is missing (OPTIMIZE FOR UNKNOWN vs. OPTION(RECOMPILE), read from the masked statement text so a hint spelled inside a comment or string literal doesn't count) or when the statement text references a local variable with no matching parameter. The row/column/annotation logic lives in a new pure PerformanceMonitor.PlanAnalysis.ParameterCard, pinned by Darling.Tests/Viewer4598Tests.cs; the WPF code-behind (ShowParameters in PlanViewerControl.Properties.cs) only builds and lays out the grid. Adds InsightParamsBrush to all three themes for the card's accent edge and header, matching PerformanceStudio's green tone.
…o viewer/4597-server-context-card
) Ports PerformanceStudio dev's Server Context insight card (erikdarlingdata/PerformanceStudio@85492a1) to the shared plan viewer used by both the Darling Viewer and Lite. The card shows the server a plan belongs to: name, edition (with the " (64-bit)" suffix trimmed), version, hardware, MAXDOP, cost threshold for parallelism, and max server memory, in PerformanceStudio's order and text. It sits first in the strip, ahead of Runtime Summary, and goes quiet when no server metadata has been captured. The row list lives in a new pure PerformanceMonitor.PlanAnalysis.ServerContextCard, pinned by Darling.Tests/Viewer4597Tests.cs; the WPF code-behind (ShowServerContext in PlanViewerControl.Properties.cs) only builds and lays out the grid, and re-runs it when ServerMetadata is set after a statement is already showing. Adds InsightServerBrush to all six theme files (Darling Viewer + Lite, each in Dark/Light/CoolBreeze) for the card's accent edge and header, matching PerformanceStudio's colour in Dark and picking matching purple tones for Light/CoolBreeze (PerformanceStudio ships only a dark theme). Not ported: PerformanceStudio's Database row (compat level, collation, isolation and scoped-config facts). PM's ServerMetadata model has no Database field yet -- it is out of scope for this change and left to a future port once that field exists.
…and seed every required server_properties column in the Lite metadata test
…oints # Conflicts: # PerformanceMonitor.Ui/PlanViewerControl.xaml.cs
…, max server memory and database settings (#4597)
…-card # Conflicts: # Darling/PerformanceMonitor.Darling.Viewer/Themes/CoolBreezeTheme.xaml # Darling/PerformanceMonitor.Darling.Viewer/Themes/DarkTheme.xaml # Darling/PerformanceMonitor.Darling.Viewer/Themes/LightTheme.xaml # Lite/Themes/CoolBreezeTheme.xaml # Lite/Themes/DarkTheme.xaml # Lite/Themes/LightTheme.xaml # PerformanceMonitor.Ui/PlanViewerControl.Properties.cs # PerformanceMonitor.Ui/PlanViewerControl.Rendering.cs # PerformanceMonitor.Ui/PlanViewerControl.xaml # PerformanceMonitor.Ui/PlanViewerControl.xaml.cs
…o plan-sync/4597-server-context-fields
…o viewer/4597-server-context-card # Conflicts: # PerformanceMonitor.Ui/PlanViewerControl.Properties.cs # PerformanceMonitor.Ui/PlanViewerControl.xaml.cs
…elds' into viewer/4597-server-context-card # Conflicts: # PerformanceMonitor.Ui/PlanViewerControl.xaml.cs
…o plan-sync/4597-server-context-fields # Conflicts: # Darling/PerformanceMonitor.Darling.Storage/DarlingServerMetadataReader.cs
…elds' into viewer/4597-server-context-card
…elds' into viewer/4597-server-context-card
erikdarlingdata
marked this pull request as ready for review
September 28, 2026 17:27
This was referenced Sep 28, 2026
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.
Fixes #4597. #4607 is merged; this is now against dev. #4604 is merged. Part of #4511.
Why
erikdarlingdata/PerformanceStudio's desktop plan viewer shows a Server Context card in its Plan Insights strip: the server a plan belongs to, its edition and version, hardware, instance-level settings such as MAXDOP and cost threshold for parallelism, and the plan's database with its compatibility level. PM's viewer had no such card, even though
ServerMetadatais now wired intoPlanViewerControlfor every Darling Viewer and Lite plan-opening site, and now carries aDatabasefield.What changes
PerformanceMonitor.PlanAnalysis.ServerContextCard.Rows(ServerMetadata?)builds the card's label/value rows in PerformanceStudio's order and text: Server (name, edition with the" (64-bit)"suffix trimmed, version), Hardware (dropped whenCpuCountis 0), MAXDOP, Cost threshold, Max memory, and now Database (name and compatibility level) when the reader found one. Returns an empty list when metadata isnull.PlanViewerControl.Properties.csgetsShowServerContext(), ported from PerformanceStudio dev'sShowServerContext(erikdarlingdata/PerformanceStudio@85492a1,src/PlanViewer.App/Controls/PlanViewerControl.RuntimeSummary.cs:203-278). It only lays out the grid; all row logic is in the pure helper above.ServerMetadata's setter now re-renders the card in place when set after a statement is already showing, matching PerformanceStudio'sMetadatasetter.InsightServerBrushto all six theme files (Darling Viewer + Lite, each Dark/Light/CoolBreeze) for the card's accent edge and header. Dark theme uses PerformanceStudio's own colour (#9B9BFF); PerformanceStudio ships only a dark theme, so Light and CoolBreeze use matching purple tones picked to sit alongside the other insight-card accents in those themes.Lite: gets this too (shared control) —
PlanViewerControlis hosted by both the Darling Viewer and Lite.Not ported
PerformanceStudio's
DatabaseMetadatacarries more than name and compatibility level: collation, isolation state, stats settings, and scoped configs. None of those other members show on PerformanceStudio's own card either — itsShowServerContextonly ever readsNameandCompatibilityLeveloffDatabase— so nothing is missing here relative to what a user sees on PerformanceStudio's card today.Test plan
Merged in the current heads of #4604 and the reader branch (twice, once for the initial reader push and once for its later
StorageCommandTimeoutTests-related update), thenorigin/devatc650606fe(five merges total, three conflicting:PlanViewerControl.Properties.csandPlanViewerControl.xaml.cseach had a spot where an old copy of one base branch's change collided with the other base's or dev's current version of a nearby method;DarlingServerMetadataReader.cshad the reader branch's ownCommandTimeoutconflict, resolved when merging the reader branch's updated head, not here. In each case the current/latest version was kept, and where both sides added distinct members both were kept side by side).Pin:
Darling/Darling.Tests/Viewer4597Tests.cs, now 13 cases: the existing full-metadata row order/text, the edition-suffix trim, null server name/edition/version, the zero-CPU-count Hardware-row drop, MAXDOP/cost-threshold staying at "0" rather than being dropped, plus two new cases for this change —Databaseset adds a "Database" / "AdventureWorks (compat 160)" row last,Databasenull adds no Database row.Darling.Tests,PerformanceMonitor.Ui,Lite/PerformanceMonitorLite.csproj,Lite.Tests,Darling/PerformanceMonitor.Darling.Viewer,Darling/PerformanceMonitor.Darling.Service— all 0 errors, 0 warnings on every log (grep -E "warning (CA|CS|IDE)[0-9]+"empty). Also fixed a pre-existing CA1310 onServerContextCard'sIndexOfcall (addStringComparison.Ordinal) so the file builds warning-free.dotnet restore PerformanceMonitor.sln --locked-mode: passes, no lock file changes needed.ifblock fromServerContextCard.Rows;Viewer4597Testswent toTotal: 11, Errors: 0, Failed: 1(Rows_DatabaseSet_AddsDatabaseRowLast). Reverted, rebuilt (0 warnings), back to green.Viewer4597Tests,Viewer4598Tests,Viewer4573Tests, thePlanSync4530*classes,PlanSync4597ServerContextFieldsLiveTests,StorageCommandTimeoutTests,ClipboardWriteCensusTests:Total: 72, Errors: 0, Failed: 0, Skipped: 3(the live class skips locally with no Postgres rig on this box; CI runs it).StorageCommandTimeoutTestsconfirms everyNpgsqlCommandinDarlingServerMetadataReader.csstill carries an explicitCommandTimeoutafter the merge that combined this branch's database-config read with Plan analysis: rule 38 reads the server's edition and MAXDOP at every entry point (#4530) #4601's deadline on the same (single, joined) query.CommentFilterAdoptionTests,DocCommentHygieneTests,McpPayloadContractCensusTests,McpToolsListBudgetTests, every*Census*class):Total: 359, Errors: 0, Failed: 0, Skipped: 1.Viewer*classes that touchPresentationFrameworktypes (ViewerDataServiceTests,ViewerWave2Tests) can't run on macOS and are skipped; neither references any file this change touches.Screenshot plan (Darling Viewer and Lite, any plan tab, on a plan whose entry point carries a database name the store has a
database_configrow for): open a stored plan, expand "Plan Insights". The Server Context card's last row should now read "Database" with the database's name and compatibility level, e.g. "AdventureWorks (compat 160)", below "Max memory". With no database on the metadata (a pasted plan XML, or no matching store row), the card shows exactly the same five rows as before this change — no blank or placeholder Database row.Update: merged current dev after #4604 squash-merged
Branch head is now
fa1a398f8, merged fromorigin/devat5aea3af896(post-#4604). Conflicts were exactly the six theme files (each just theInsightServerBrushline vs. dev's Parameters-card additions — resolved by keeping both brushes) andPlanViewerControl.xaml/.xaml.cs(the Parameters/Wait StatsGrid.Columnindices shifting to make room for Server Context at column 0, and theServerAccentBrushproperty — resolved by keeping this card's column numbering, 0–4, and adding theServerAccentBrushaccessor alongside dev's Parameters one). No duplicatex:Key/x:Names; strip order is Server Context, Runtime Summary, Missing Indexes, Parameters, Wait Stats.Re-ran after the merge:
Darling.Tests,Lite/PerformanceMonitorLite.csproj,Lite.Tests,Darling/PerformanceMonitor.Darling.Viewer): all 0 errors, 0 warnings.dotnet restore PerformanceMonitor.sln --locked-mode: passes.Viewer4597Tests,Viewer4598Tests,Viewer4573Tests,StorageCommandTimeoutTests,DocCommentHygieneTests,CommentFilterAdoptionTests:Total: 135, Errors: 0, Failed: 0, Skipped: 0.PlanSync4597ServerContextFieldsLiveTests:Total: 276, Errors: 0, Failed: 39— every failure isLivePostgresStoreFixturerefusing127.0.0.1:5432(no Postgres rig on this box, same class of skip as before); none is a real regression from the merge.Update: merged #4601's squash-merge commit into #4602, then #4607, then this branch
Branch head is now
3883064a8, built by mergingorigin/plan-sync/4597-server-context-fields(itself remerged toff9013140) intoviewer/4597-server-context-card;origin/devat209aca7fewas already an ancestor by that point, so the directdevmerge was a no-op (Already up to date). No conflicts in this merge step itself — the base-branch merge upstream carried the resolutions.Re-ran after the merge:
Darling.Tests,Lite.Tests,Lite/PerformanceMonitorLite.csproj,Darling/PerformanceMonitor.Darling.Viewer,Darling/PerformanceMonitor.Darling.Service): all 0 errors, 0 warnings.dotnet restore PerformanceMonitor.sln --locked-mode: passes.Viewer4597Tests,Viewer4598Tests,Viewer4573Tests,PlanSync4597ServerContextFieldsLiveTests,PlanSync4530*,StorageCommandTimeoutTests, plus the census family:Total: 341, Errors: 0, Failed: 41, Skipped: 0. All 41 failures areLivePostgresStoreFixturerefusing127.0.0.1:5432(no Postgres rig on this box); none is a regression from the merge.CHANGELOG
SECTION: Added
ENTRY: - Plan viewer: a Server Context card ([#4614]) - The Plan Insights strip now opens with a Server Context card, as in PerformanceStudio's desktop viewer. It shows the server a plan belongs to: its name, edition and version, CPUs and memory, MAXDOP, cost threshold for parallelism, max server memory, and the plan's database with its compatibility level, from what the collector has stored for that server.
REF: [#4614]: #4614