Skip to content

The Long-Running Query opt-out knob gets its Darling store home: V135 adds the two lists to config_alert_settings with the production read's seeds as their DEFAULT, wired through the service, the Viewer, the probe and both SKUs' get_alert_settings / update_alert_settings twins (#3653 A5, Q5) - #3736

Merged
erikdarlingdata merged 1 commit into
devfrom
fix/3653-lrq-knob-rung
Sep 19, 2026

Conversation

@erikdarlingdata

Copy link
Copy Markdown
Owner

Mechanism

#3734 gave both SKUs the Long-Running Query opt-out knob — program_name PREFIXES and exact login_names whose sessions the alert does not evaluate, seeded from the 7-day production read (SQLAgent - TSQL JobStep; NT AUTHORITY\SYSTEM, NT AUTHORITY\NETWORK SERVICE) — editable on Lite, and on Darling the seeds and nothing else. A Darling alert knob has no rung-free home: the store row is authoritative (StoreConfigProvider.ApplyToConfig replaces config.Alerts wholesale on every load, so a darling.json-only member reads as configured and is dead), and McpAlertSettingsKeyTests pins both SKUs' get_alert_settings to one shape, so neither SKU could publish the knob over MCP until Darling could store it. This PR is that store home, one rung after #3730's V134.

V135 (lrq-exclusion-knob): long_running_query_excluded_program_name_prefixes and long_running_query_excluded_logins on config.config_alert_settings, text[] NOT NULL, DEFAULT the two seeded arrays — the one knob rung on this row that ships a non-empty default, and deliberately: a pre-rung row must read as exactly what DarlingAlertSettings returned before the rung (the seeds, since #3734) and what Lite ships, so the two SKUs and the two sides of the rung evaluate one population. An operator's cleared list is stored as an explicit '{}' and honoured — present-and-empty is a decision, and nothing re-seeds it. AlertsConfig (darling.json) and the Viewer's AlertSettingsRow initialise to the same seeds; LongRunningQueryExclusionKnobRungTests pins the rung's DEFAULT literal, both C# initialisers and LongRunningQueryExclusions.DefaultProgramNamePrefixes / DefaultLogins equal. IF NOT EXISTS, schema-qualified, no reload beacon of its own (V17's statement-level trigger already bumps config_version), no GRANT (table-level grants, no column carve).

Plumbing, all at the appended ordinals (the four-parallel-sequences trap every knob rung on this row walks): StoreConfigProvider seeds them as $69/$70 through the shared normaliser and reads them at 67–68 (a column selected but not read resets the knob on every worker start); DarlingAlertSettings forwards them by reference like ExcludedDatabases, so the store's hot-reload reaches the engine on its next sweep; the Viewer's ViewerDataService.AlertSettings select/upsert bind them as $68/$69 and read 67–68, and its Settings window gets two boxes (AlertLrqExcludedProgramNamePrefixesBox / AlertLrqExcludedLoginsBox — named so the #1840 wiring census sees them: gated on the master switch, and Restore Defaults puts the seeds back, not empty boxes); the viewer probe gains the V135 column sentinel as the top arm (V134's "I am the top rung" claims move to this rung's tests, as V134 moved V133's); DarlingAlertReader.AlertSettingsSelectSql reads 67–68 for get_alert_settings; update_alert_settings accepts long_running_query.excluded_program_name_prefixes / .excluded_logins through the normaliser (pass the full list; an empty array clears that arm); Lite's get_alert_settings publishes the same two keys, so the parity pin holds.

Docs. Every description — both get_alert_settings, update_alert_settings, the Viewer's Settings hint, darling.sample.json, DarlingConfig, the V135 doc comment, the Darling README's settings table and ladder table — states the two rules (prefix / exact, case-insensitive, no wildcard grammar), the four classes the read found (job steps → prefix default; the two NT AUTHORITY logins → login default; the application's admin login → deliberately not a default, because it carries the job wave and real ad-hoc long-runners; named humans → never), the seeds' grounding ("7-day read of one large production store"), and that the seeds are defaults an operator can clear.

Evidence

  • One large production store, 7 days: SQL Agent job steps ~460 sessions/week across 11 single-server jobs (medians 35–62 min); NT AUTHORITY\SYSTEM / NETWORK SERVICE ~70 sessions across 42 servers, medians 4.8–8.6 days, 300K+ snapshots, CDC-capture shaped; the admin login carries the job wave and ad-hoc long-runners; named humans 3 sessions/week.
  • Live PostgreSQL 18 (Docker): MigrateAsync applies V135; the store's information_schema.columns.column_default for the two columns reads back as ARRAY['SQLAgent - TSQL JobStep'::text] and ARRAY['NT AUTHORITY\SYSTEM'::text, 'NT AUTHORITY\NETWORK SERVICE'::text]; the scratch seed → read round-trip carries a cleared login list back empty (not re-seeded) and a padded, case-duplicated prefix list back normalised.

Why this shape

What it does NOT do

Tests

  • LongRunningQueryExclusionKnobRungTests (new): the rung is registered at the top of a dense ladder; adds both columns schema-qualified with the seeds as DEFAULT (pinned equal to the engine constants, AlertsConfig and AlertSettingsRow.Defaults()), doc comment names the four classes; the probe's three sites carry the sentinel and a fully-migrated store maps to exactly StorageVersion.SchemaVersion; every settings-row surface names both columns (service read at 67–68 + normalised seed, MCP select + report + accept, Viewer select/upsert/reader); the Settings boxes prefill/save/gate and restore the seeds; the Viewer bind round-trips normalised at the appended ordinals; the MCP reader's positional record agrees with its SELECT; the seam forwards by reference, defaults to the seeds, honours a cleared list through ApplyToConfig; both MCP payloads spell the knob identically and both descriptions state the rules, the four classes, the grounding and the admin-login reason.
  • TimeHonestyRungTests: top-rung claims handed off (ladder pin RungVersion < SchemaVersion, probe ordinal < arity - 1, arm returns 134); its live climb now drops V135's columns and stamp too and expects two rungs (the applier skips anything at or below MAX(version)).
  • DarlingAlertTuningKnobsTests: seam defaults are the seeds; the live scratch seed → read round-trip carries the two lists (cleared login list stays empty; prefix list normalised) and reads the column DEFAULTs back from the catalogue.
  • SelfDiskWarnGbFloorRungTests [^3]; DarlingMcpAlertToolsTests round-trip sample carries non-default lists; LongRunningQueryExclusionsTests Darling half flips to the by-reference shape.
  • Executed here: the real Darling.Tests.dll (WindowsDesktop stripped) on this Mac against PostgreSQL 18 in Docker — 402/402 across the rung, probe, seed/read, viewer bind, MCP, wiring and engine classes; the full suite 11,451 with 191 platform reds (PresentationFramework / SqlClient ConfigurationManager / Windows paths / DPAPI), the same baseline as before the change. Red-first: with the V134 live climb unadapted, MigrateAsync applied 0 rungs and DarlingAnalysisStoreTests counted 133 stamps for 134 scripts — the exact skip-forever hazard the density pin describes.

Depends on #3734 (merged to dev at 12:52Z; this branch is on top of it).

Partial #3653 — item 6 (Q5 — the Darling store home + MCP twins, V135)

… adds two text[] columns to config_alert_settings whose DEFAULT is the production read's seeds, wired through the service seed/read, the Viewer's Settings window and select/upsert, the viewer probe's top arm, and both SKUs' get_alert_settings / update_alert_settings twins (#3653 A5, Q5)

#3734 gave both SKUs the knob - program_name PREFIXES and exact logins
whose sessions the Long-Running Query alert does not evaluate, seeded
from the 7-day production read (SQLAgent - TSQL JobStep; NT AUTHORITY\
SYSTEM and NT AUTHORITY\NETWORK SERVICE) - editable on Lite, and on
Darling the seeds and nothing else, because a Darling alert knob has no
rung-free home: the store row is authoritative (ApplyToConfig replaces
config.Alerts wholesale), so a darling.json-only member is dead, and
McpAlertSettingsKeyTests pins both SKUs' get_alert_settings to one
shape, so neither could publish it until Darling could store it. This
is that store home, one rung after #3730's V134.

V135: long_running_query_excluded_program_name_prefixes and
long_running_query_excluded_logins, text[] NOT NULL, DEFAULT the two
seeded arrays - the one knob rung on this row that ships a non-empty
default, so a pre-rung row reads as exactly what DarlingAlertSettings
returned before the rung and what Lite ships, and the two SKUs and the
two sides of the rung evaluate one population. An operator's cleared
list is stored as an explicit '{}' and honoured: present-and-empty is
a decision, and nothing re-seeds it. AlertsConfig and the Viewer's
AlertSettingsRow initialise to the same seeds (pinned equal to the
rung's DEFAULT and to LongRunningQueryExclusions.Default*). No reload
beacon (V17's trigger), no GRANT (table-level), IF NOT EXISTS.

Plumbing, all at the appended ordinals: StoreConfigProvider seeds them
as $69/$70 and reads them at 67-68 (a column selected but not read
resets the knob on every worker start); the Viewer's select/upsert bind
them as $68/$69 and read 67-68, its Settings window gets two boxes
(AlertLrqExcluded*Box, so the #1840 wiring census sees them: gated on
the master switch, Restore Defaults puts the SEEDS back); the viewer
probe gains the V135 sentinel as the top arm (V134's top-rung claims
move here, as V134 moved V133's); DarlingAlertReader reads 67-68 for
get_alert_settings; update_alert_settings accepts
long_running_query.excluded_program_name_prefixes / .excluded_logins
through the shared normaliser (empty array = cleared arm); Lite's
get_alert_settings publishes the same two keys. Every description
states the two rules, the four classes, the seeds' grounding and why
the admin login is not a default.

TimeHonestyRungLivePostgresTests' simulated climb drops V135's columns
and stamp too and expects two rungs: the applier skips anything at or
below MAX(version), so a "one rung short" store must be short of the
TOP, which this rung now is.

Executed on this Mac: the real Darling.Tests.dll (WindowsDesktop stripped)
against PostgreSQL 18 in Docker - 402/402 across the rung, probe, seed/
read, viewer bind, MCP and engine classes (the seed -> read scratch
round-trip carries a cleared login list back empty and a padded prefix
list back normalised; the store's column DEFAULTs read back from the
catalogue as the seeds); full suite 11,451 with 191 platform reds
(PresentationFramework / SqlClient ConfigurationManager / Windows
paths), the same baseline as before this change.

Partial #3653 - item 6 (Q5). Does not close it.
@erikdarlingdata
erikdarlingdata merged commit dc1ddeb into dev Sep 19, 2026
7 of 8 checks passed
@erikdarlingdata
erikdarlingdata deleted the fix/3653-lrq-knob-rung branch September 19, 2026 13:38
This was referenced Sep 19, 2026
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.

1 participant