[pull] main from erikdarlingdata:main - #15
Merged
Merged
Conversation
…n-alerts # Conflicts: # CHANGELOG.md
…er-latch Fix: Azure SQL DB outage permanently wedged database-scoped collection (#1506)
… Changes tab Part 1 (collapse, behavior-preserving): the config-change diff (server / database / trace-flag DRIFT computed from append-only config snapshots) was hand-duplicated in the Darling viewer (ViewerDataService.ConfigChanges Diff*) and the headless MCP host (DarlingConfigHistoryReader Compute*). Hoist the one source into PerformanceMonitor.Common.ConfigChangeDiff: the three pure diff algorithms, the snapshot INPUT records, the change OUTPUT records carrying the pure-derived columns (requires_restart / change_description / scope / status text), and the 27 database-config setting names. The viewer's ...Row view-models become thin display wrappers (adding only the ViewerTimeHelper timezone render); the service reader deletes its diff/records/setting-names and calls the shared class, with the MCP tools passing DateTime.MaxValue as the no-op upper edge so the shared both-edges diff reproduces their prior unbounded-read behavior. No third copy. Same one-source pattern as the #1507 significance collapse. The Darling config-history tests are repointed to the shared class and stay green. Part 2 (Lite tab): new LAST top-level Configuration Changes tab (index 19, after System Events, nothing renumbered; RefreshVisibleTabAsync case 19 == XAML index 19) with three sub-tab grids (Server / Database / Trace Flag config changes) consuming the shared ConfigChangeDiff over the DuckDB snapshot views v_server_config / v_database_config / v_trace_flags. The read upper-bounds at the window end (keeps the pre-window baseline), capture_time renders through ServerTimeHelper.FormatServerTime, the #1319 database filter is honored, and every Darling grid column is reproduced. Real-DuckDB round-trip reader tests plant two captures encoding a known change and assert the diff. Common + Darling + Lite only; no Full Dashboard, no install/*.sql. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-alerts Lite connection alerts + generic webhook channel (#1506)
…anges-tab # Conflicts: # CHANGELOG.md
…nges-tab Collapse config-diff twin to shared Common + Lite Configuration Changes tab (Tier-1 parity)
…er-1 parity) Port the Darling viewer's Expensive Queries view to Lite as the LAST sub-tab of the Queries tab (sub-index 6, after Query Heatmap — nothing else reindexed; the Queries inner switch gains case 6 while the top-level Queries tab stays index 2). One grid UNIONs the three query engines Lite already collects — query_stats (Query Stats), procedure_stats (Stored Procedure/Trigger/Function), and query_store_stats (Query Store) — each grouped and TOP-20-per-source ranked by AVERAGE worker (CPU) time, then merged, re-ranked by average worker time and capped at 20, mirroring the Dashboard's report.expensive_queries_today and Darling's GetUnifiedExpensiveQueriesAsync. Reader LocalDataService.ExpensiveQueries.cs adapts the Postgres/T-SQL UNION to DuckDB against the v_query_stats / v_procedure_stats / v_query_store_stats archive views: the query_stats/query_store arms SUM the collected deltas / weight per-interval averages by execution_count, a LATERAL fetches each group's latest text + stored plan, every arm is both-sides window-bound on collection_time and honors the #1319 database filter, and the us->ms/sec + KB/page->MB conversions run in SQL like the Dashboard view's outer projection. Named UnifiedExpensiveQueryRow / GetUnifiedExpensiveQueriesAsync to avoid collision with Lite's FinOps-cost ExpensiveQueryRow. The stored plan rides IN-ROW, so View Plan / Copy Repro Script open it with zero extra reads via the shared DataGridContextMenu — mirroring the Top Queries sub-tab (View Plan on the in-row plan; Get Actual Plan re-executes the runnable statement sources; both no-op cleanly for module sources and plan-less rows). Store-driven deviations, each faithful to Lite's store: Query Stats objects are the constant 'Adhoc', all functions collapse to one 'Function' label, the Query Store grant is pages->MB (x8/1024), and the Query Store arm carries no stored plan and no plan_handle (Lite's query_store_stats stores neither) so its plan actions gate off. Every Darling grid column reproduced. Real-DuckDB round-trip tests (ExpensiveQueriesReaderTests) assert the cross-source ranking by avg worker time, the unit conversions, the source labels + object-name shapes, the in-row plan (and the Query Store no-plan/no-handle deviation), delta summing across snapshots, the #1319 filter, and window bounding. Full Lite.Tests green (1231 passed, 0 failed); Lite build clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…queries-tab Lite: Expensive Queries sub-tab (unified cross-source ranked list, Tier-1 parity)
Port Darling's Blocking Stats sub-tab to Lite: a 2x2 chart grid + summary strip showing blocking AND deadlock SEVERITY over the window (the "getting WORSE, not just more frequent" signal), the severity companion to Lite's existing count-only Blocking Trends sub-tab. Appended as the LAST Blocking sub-tab (sub-index 4, after Deadlocks) so nothing reindexes; RefreshBlocking Async's subTabOnly switch gains case 4 and the full-refresh path renders it. Blocking stays top-level index 8. Reader (LocalDataService.BlockingStats.cs) adapts Darling's aggregates to DuckDB: block-duration SUM/MAX/AVG(wait_time_ms) per minute over the same XE-preferred + DMV-fallback (WHERE NOT EXISTS) union the count trend uses (honoring the #1319 DB filter on both arms), and a deadlock-severity aggregate over deadlock_graph_xml on the same v_deadlocks/collection_time window as the count (uncapped), parsed off-thread with Lite's own DeadlockProcessDetail .ParseFromRows and bucketed by minute (victim_count + total/max/avg wait). Collapse check: Darling's deadlock-severity computation is NOT a viewer<-> service twin -- the service/MCP side hosts only count trends and deliberately omits a blocking_deadlock_stats aggregate, and the Darling viewer already parses via shared Common.DeadlockGraphParser -- so per the brief Lite reuses its own existing ParseFromRows (internally consistent with its Deadlocks grid) rather than adding a third copy. Nothing on the Darling side touched. Four charts (ServerTab.BlockingStats.cs) mirror Darling with Lite's chart idioms (ChartStyle/ChartHoverHelper, SeriesColors/ChartPalette, UtcOffset Minutes axis, Y-floor-at-0, window-padded scatter), wired into the Blocking TabControl + ServerTab.xaml.cs init/dispose. Real-DuckDB round-trip tests (BlockingStatsReaderTests) assert the duration aggregate, the XE->DMV fallback, the #1319 filter, window bounding, and the deadlock-severity aggregate reconciling with the deadlock count. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tats-tab Lite: Blocking Stats severity sub-tab (Tier-1 parity)
Adds a LIVE, on-demand "what is running right now" DMV snapshot to the Darling viewer, delivered through the Stage-2 command plane exactly like execute_actual_plan / fetch_plan: the store-only viewer enqueues a new fetch_active_queries command, the service runs the query on the target server's live connection and returns the rows in result_json, and the viewer renders them in a new "Current Active Queries" sub-tab. Command plane (mirrors fetch_plan): - New CommandKind.FetchActiveQueries + "fetch_active_queries" case in DarlingCommandExecutor.ResolvePlan (requires target_server_id, no args) and the RunAsync dispatch to IDarlingCommandHost.FetchActiveQueriesLiveAsync. - WorkerCommandHost + DarlingWorker.RunFetchActiveQueriesLiveAsync resolve the runtime under the servers lock, return legible not-monitored / not-connected / timeout / permission / sql-error outcomes, and cap the SQL read at 30s (under the viewer's 60s poll budget). - Read-only DMV read (not consent-class like execute_actual_plan), but it rides the same read-write-seat-only enqueue as every other command. DMV query REUSED (not reinvented): - DarlingCollectorRunner.FetchRowsAsync runs the shared QuerySnapshotsCollector (BuildQuery + ReadAsync) against the live connection and returns the rows WITHOUT writing to the store, building the SAME CollectorContext the scheduled sweep builds, so the live snapshot carries the same columns as the stored one. Viewer: - ViewerDataService.RequestActiveQueriesLiveAsync enqueues, polls, deletes the (large) row, and parses result_json into ViewerQuerySnapshotRow (the stored grid's model), with read-only-seat / timeout / failure handling. - New "Current Active Queries" sub-tab (index 2, right after the stored Active Queries tab) with a Refresh button; on-demand only (never auto-fetched). Estimated/Actual plan buttons reuse the stored handlers. Tests (Darling.Tests green; build clean): - Pins the new command constant viewer<->executor, the ResolvePlan case, and the full service-serialize -> viewer-parse wire contract (no live SQL Server needed), plus timeout/failure mappings and the poll-budget ordering. Live fetch_active_queries executor round-trip gated on DARLING_TEST_PG like the fetch_plan one. Darling-only: no Lite, Dashboard, or install/*.sql changes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tive-queries Darling: live Current Active Queries via service-mediated command
Port the Dashboard's Query Store Regressions grid to the Darling viewer as a new Queries sub-tab, inserted at index 6 (after Query Store by Duration, matching the Dashboard's Query Store -> Query Store Regressions adjacency). Every sub-tab index uses a named constant, so Expensive Queries/Query Heatmap only shift. - ViewerDataService.QueryStoreRegressions.cs: the Postgres port of the Dashboard's report.query_store_regressions TVF against query_store_stats -- baseline (before the window) vs recent (in-window) averages split on collection_time, CPU-regression > 25% gate, execution-count-weighted added-duration ranking, TOP 50, duration-driven severity bands; honors the #1319 database filter; row VM reproduces every column. - Loader + switch case + constant (Queries.cs), FilterManager (Filters.cs), double-click history reusing QueryStoreHistoryWindow with plan_id 0 (History.cs), plan-less Copy Repro from the query-text sample (CopyExport.cs), and the XAML sub-tab (QueryGridRowStyle, no slicer/comparison -- matching the Dashboard grid and the sibling grid-only tabs). - Tests: SQL string pins (base table, baseline/recent split, CPU gate, ranking/cap, severity, casts, DB filter, PG dialect), row display, key mapper, Copy Repro, and a gated live round-trip (baseline-vs-recent detection). Darling-only: no Lite, Full Dashboard, or install/*.sql changes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…essions Darling viewer: Query Store Regressions sub-tab (Dashboard parity)
Restore three classifications the deprecated Dashboard's report.* / config.critical_issues SQL made but the ported shared analysis engine had dropped. All three are pure FactScorer additions over facts the collectors already emit (no collector/schema/install change), so they light up in Lite, the Dashboard, and Darling recommendations at once; each cites its source SQL line in a code comment. - Query Store disabled: INFO advisory folded into DB_CONFIG, detected as query_store_on_count < database_count (install/50:83). - Security-cache (TokenAndPermUserStore) growth: flat WARNING when the USERSTORE_TOKENPERM clerk >= 1 GB, off the context-only MEMORY_CLERKS fact (install/50:562,583). - Runnable-queue / worker pressure: standalone ScoreCpuFact arm on total_runnable_tasks_count tiered > 50/20/10 plus the small-box runnable_tasks_warning fallback (install/47:1839-1844); additive to and distinct from the #1494 THREADPOOL amplifier, which is unchanged. Advice wired for the new/expanded root keys (MEMORY_CLERKS + RUNNABLE_TASKS blocks; Query Store folded into ComposeDbConfig) so the cards are not contentless, sourced from the Dashboard's own message/recommendation text. FactScorer tests added in both Lite.Tests and Dashboard.Tests (tiers fire at the right band, stay silent below the bar, existing arms unchanged). The Lite clean-server seeder now defaults Query Store ON (the healthy value) so the QS-off arm stays dormant in fixtures not exercising it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wraps the 18 MCP tools Lite lacked vs Darling as [McpServerTool] wrappers over readers Lite already has: get_latch_stats / get_spinlock_stats / get_plan_cache_bloat / get_cpu_scheduler_pressure / get_resource_semaphore / get_default_trace_events / get_daily_summary / get_server_config_changes / get_database_config_changes / get_trace_flag_changes, and the 8 get_health_parser_* tools. io_issues/cpu_tasks got thin reader adds off the shared Common.SystemHealthParser (parse reused, not reinvented). KnownLiteMissingMcpTools drained to empty (the CI inventory-pin ratchet). The get_blocking rename is deliberately NOT done here (breaking; held for explicit sign-off). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ports # Conflicts: # CHANGELOG.md
…-arms-batch1 # Conflicts: # CHANGELOG.md
…orts Port 18 MCP tools to Lite (Tier-2 Lite<->Darling MCP parity)
…-arms-batch1 # Conflicts: # CHANGELOG.md
…arms-batch1 Add 3 Tier-2 issue-classification arms to the shared FactScorer
Two sourced pure-scorer arms (land in Darling + Lite; no collector change -- both read data already in existing fact metadata): - TempDB version-store pressure by ABSOLUTE size (max_version_store_mb): >5000 CRITICAL / >2000 HIGH / >1000 MEDIUM, Math.Max'd into TEMPDB_USAGE alongside the existing space-fraction score. Source: report.tempdb_pressure (install/47:1431-1433). - TempDB PAGELATCH_UP allocation contention: absolute wait_time_ms > 10000 -> MEDIUM. Source: report.tempdb_contention_analysis (install/47:2515). The CRITICAL allocation_contention_warning is a tempdb-scoped flag not carried in the server-wide wait fact, so this is scoped to the PAGELATCH_UP MEDIUM tier. Base caps at 1.0 (WARNING); CRITICAL earned via corroboration. Sourced advice added; FactScorerTests in Lite + Dashboard (67 Lite FactScorer tests green). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tier-2 batch-2a: tempdb-deep analysis arms (version-store size + PAGELATCH)
CI: run the gated-live Darling PostgreSQL suite on PRs, not only nightly (#1587)
…1599) The build job built Lite.Tests + Installer.Tests + Darling and published all five apps on EVERY non-doc PR, regardless of what changed - the bulk of its wall-clock. Gate each product's build/test/publish with a paths-filter that encodes the real ProjectReference graph: - product dirs (Lite/ Dashboard/ Installer/ Darling/) never reference each other, so a change confined to one builds only that product - a shared PerformanceMonitor.* core lib fans out to Lite + Dashboard + Darling (NOT the CLI Installer - it references only Installer.Core) - Installer.Core fans out to Installer + Dashboard - a root build file (solution, global.json, restore config, this workflow) rebuilds everything - markdown-only changes under a product dir short-circuit to a green no-op (the filters exclude **/*.md, so a docs PR never trips a build with .NET setup skipped) A Darling-only PR - the common case - no longer builds/tests Lite or the Installer or publishes the four other apps, and it shrinks further as Full/CLI move to maintenance. No coverage lost: products can't break each other; shared changes trigger the fan-out. darling-pg (#1598) untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…oducts CI: gate PR build/test/publish per product via the dependency graph (#1599)
Adds seven MCP tools to the Darling server so an MCP client can build and
manage Custom Views (CV2) programmatically instead of only via the web
editor: list_custom_views, get_custom_view, validate_custom_view,
create_custom_view, update_custom_view, delete_custom_view, and
run_custom_view_panel (compile + run a single composed panel and return
{sql, rows, annotations} for a self-test loop).
No divergent second implementation: every tool routes through the existing
authority. Persistence is the same CustomViewStore; structural validation is
the same DarlingWebEndpoints.ValidateDefinition (through ComposeSpec.TryParsePanel
and the hand-authored measure catalog); and the panel run is the shared
RunComposedPanelAsync extracted from the web /api/compose/run endpoint, which
now backs both surfaces. create/update always validate before persisting.
The returned view shape reuses the web BuildFullViewNode/BuildSummariesNode.
Security (scoped, deliberate): the mcp role is granted INSERT/UPDATE/DELETE on
only config.custom_views via role provisioning (not a migration), mirroring the
viewer role's single-table grant for the web composer. A token-holder can author
custom views but still cannot reach the config_command pivot or the carved secret
columns, and a composed query names only collect.* tables. The README MCP
blast-radius section and the MCP instructions are updated to state the widened write.
Tests: provisioning-grant pins (unit) + validate/validate-before-persist envelopes
(ungated) + a gated-live round-trip through the tools against a real PostgreSQL, and
the security-split live test extended to prove the mcp role can write config.custom_views.
The cross-app Lite<->Darling MCP tool-inventory ratchet (Lite.Tests
CrossAppMcpToolInventoryPinTests) records the seven new tools as Darling-only (CV2 is a
central-store feature Lite has no twin for). Full Darling.Tests: 2767 passed / 0 failed /
143 gated-live skipped (local; the gated-live suite runs on CI's darling-pg PR job).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts: # CHANGELOG.md
… rows, live create-invalid, search_path fix
Strengthens DarlingMcpCustomViewToolsLivePostgresTests per review, no downscoping:
- run_custom_view_panel now runs against SEEDED collect.wait_stats and asserts NON-EMPTY
{sql, rows} come back (delta_wait_time_ms summed into hourly buckets), proving the composed
panel's data flows end-to-end, not just that the SQL compiles.
- Adds a LIVE create-with-invalid-definition assertion: the tool returns 'invalid' AND no row
is stored (validate-before-persist proven on the real store, alongside the ungated dead-store test).
- Opens the seed connection with the explicit collect/config search_path (like the tool data source)
so the helper's bare `servers` / `wait_stats` resolve regardless of pool state — a raw cs connection
can reuse a stale pre-migration session whose search_path is only `public` (surfaced only in a full run).
Verified against a real throwaway PostgreSQL + TimescaleDB stood up from the bundled pg-runtime
(exactly as CI's darling-pg job does, DARLING_TEST_PG set): the gated-live round-trip RAN (not skipped)
and PASSED, and the full Darling.Tests suite is 2904 passed / 0 failed / 6 skipped with the gated-live
tests INCLUDED (the 6 skips need DARLING_TEST_SQL / DARLING_TEST_PGRUNTIME, none of them mine).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Darling MCP: create and manage Custom Views (CV2) over MCP
…up + firewall) Four one-shot verbs let a headless operator toggle the MCP + web-dashboard endpoints and open/close their firewall rule in one elevated action: --enable-mcp / --disable-mcp / --enable-web / --disable-web. Closes two headless-deployment gaps: - No supported way to enable/disable an endpoint on a box without the WPF Viewer's Settings. After first run darling.json's mcp.enabled/web.enabled are only a SEED; the store (config.config_service.mcp_enabled/web_enabled) is the live switch. Each verb writes the store via a targeted UPDATE whose BEFORE-UPDATE self-bump trigger increments config_version, so the worker hot-reloads within one sweep (no restart). Never touches config_version, paused, or the other endpoint's flag. - The service runs as a virtual service account that cannot modify Windows Firewall, so its best-effort self-reconcile silently fails. When the endpoint's darling.json network block opts into LAN exposure, each verb (run elevated) opens/removes the SAME scoped, idempotent-by-DisplayName rule the host reconciles; not elevated -> prints the exact elevated command as a handoff (the store toggle already succeeded, so a non-elevated shell is never a failure). A firewall failure is non-fatal. Managed-mode only (BYO governs its own config_service + exposure); Windows-only (DPAPI credential decrypt + WindowsPrincipal + firewall), same guard shape as --print-viewer-connection. Wired into IsKnownVerb, UsageText, and the Program dispatch (allow-list + dispatch kept in sync). The two host firewall-rule-name builders are now internal so the CLI reconciles the exact same DisplayName. Tests (Darling.Tests): pin the four targeted store-write SQL strings (right flag, updated_by='cli', WHERE id=1, never config_version/paused/other flag), verb recognition + classify wiring, the pure firewall-step classifier, the shared rule names, and one gated-live (DARLING_TEST_PG) test proving enable/disable flip the flag AND self-bump config_version (transaction rolled back). Gated-live skips in the normal unit run. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…N-exposure section Adds a "Headless enable/disable + firewall" subsection beside --configure-network: the four verbs flip the live config_service store flag (the first-run darling.json enabled is only a seed) and reconcile the same scoped firewall rule, elevated or as a printed handoff. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…M view authoring #1600 added the seven Custom Views authoring tools but gave an MCP client no way to DISCOVER the compose vocabulary. The tool descriptions give the panel shape and say "iterate until valid", but no tool enumerates the legal source/measure/dimension/aggregate/unit/viz identifiers, and validate errors name the first problem without listing valid values ("unknown source 'X'" never says what sources exist). An assistant asked to build a view had to guess names blind - the wall hit while dogfooding, cleared only by reading MeasureCatalog.cs source a customer's assistant cannot. Add a read-only describe_custom_view_catalog tool that returns the SAME BuildComposeCatalogNode the web composer's /api/catalog picker binds to (measures with source/kind/validAggregates/allowedDimensions/units/appliesTo, dimensions, unit families, aggregates, timeBuckets, filterOps, viz). The MCP server instructions now direct clients to call it FIRST before authoring; it joins the /api/read exclusion set like the other Custom Views tools (served by its own endpoint, not the 1:1 read mirror). No divergent catalog - one source of truth. Static reference data: no store, no server, not a write. Tests: updated tool-surface / Gemini-schema / required-param pins (now eight Custom Views tools), the /api/read parity reflection, and a new pin that the tool surfaces a known measure with its composable fields. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ews write The startup "Least-privilege roles ready" log still described the mcp role as "viewer's reads + INSERT on analysis_findings/analysis_muted" — omitting the config.custom_views write #1600 granted it (the same grant the custom-view MCP tools, and describe_custom_view_catalog's neighbors, rely on). One-line log-accuracy leftover from #1600, folded in here since it's the same surface. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… as Lite-missing Lite.Tests CrossAppMcpToolInventoryPinTests asserts Darling's MCP tool set is a superset of Lite's, with a ratchet allow-list of Darling-only tools Lite has no twin for. describe_custom_view_catalog is Darling-only by the same architecture as the #1600 CV2 tools (Lite has no web composer or config.custom_views), so it joins KnownLiteMissingMcpTools. This CI Lite.Tests check is not in the Darling build, which is why the Darling-only local run didn't surface it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…covery-tool Darling MCP: describe_custom_view_catalog (compose vocabulary for LLM view authoring)
…t-cli-verbs # Conflicts: # CHANGELOG.md
…-cli-verbs Darling: --enable/disable-mcp/web CLI verbs (headless endpoint bring-up + firewall)
…t's healthy-job assertion The CompressionJobSelfHeal gated-live test asserts a freshly-applied compression policy job is NOT flagged as stuck. But a just-added TimescaleDB job can momentarily read next_start = '-infinity' in job_stats before its background scheduler assigns the first real next run - and the stuck-job detector is CORRECT to flag -infinity - so asserting immediately after ApplyCompressionPolicy raced that window and intermittently false-failed on a slow CI runner. Fix: arm the job with a real future next_start (via the same alter_job the self-heal uses), then wait for the catalog to reflect a non-(-infinity) next_start before the "not flagged" assertion. Bounded to 30s, failing loudly if it never settles (a job that stays -infinity IS genuinely stuck and must not silently pass). Test-only; the detector and self-heal are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…sion-selfheal-flake
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ion-selfheal-flake Darling.Tests: settle the compression self-heal healthy-job assertion (gated-live flake)
…delete_mute_rule) Add three Darling-only MCP write tools to DarlingMcpAlertTools so an MCP client can tune a user's alerting conversationally, the sibling of the #1600 Custom Views write tools: - update_alert_settings: a PARTIAL update of the singleton config_alert_settings row, validated against the SAME ranges/enums the Viewer's Settings window enforces (SettingsWindow.BuildAlertRowFromControls). Validate-before-write: an out-of-range value or an unknown field (top-level or nested) returns {status:"invalid"} and writes nothing. Applies ONLY the provided columns via a targeted parameterized UPDATE ... WHERE id = 1; the config-table trigger self-bumps config_version so the service hot-reloads within one sweep. - create_mute_rule / delete_mute_rule: reuse the SAME PgMuteRuleStore get_mute_rules reads through, with the Viewer's GUID id-generation. Grant (least-privilege mcp role, in role provisioning, NOT a migration): INSERT/UPDATE/DELETE on config.config_mute_rules and UPDATE on the singleton config.config_alert_settings, mirroring how #1600 granted config.custom_views. Plus a COLUMN-level UPDATE on config_service (config_version, updated_at): the config_alert_settings bump trigger (config_bump_version) is SECURITY INVOKER and UPDATEs config_service AS the writing role, so without this every settings write would fail 42501 in production - and the superuser-run gated-live tests would never catch it. The column grant lets mcp bump the reload beacon but NOT flip paused / capture_plans / mcp_enabled / mcp_port. Also: the MCP instructions document the three tools + the read-modify-write flow and recount the tool prose (82 -> 85); the cross-app tool-inventory ratchet lists them as Darling-only (Lite has no central alert store); the three write tools join the /api/read exclusion set (writes, no read endpoint); the README MCP blast-radius + roles table are updated. Tests: six-tool surface pin, Gemini-clean schema + required-params, and validate-before-write (a bad/unknown partial update returns invalid WITHOUT opening a connection); a DarlingManagedRoles grant pin; the live security test now proves the mcp role can UPDATE config_alert_settings (the beacon fires) but cannot flip paused; and one gated-live round-trip proves update_alert_settings flips a threshold + self-bumps config_version and create_mute_rule -> get_mute_rules -> delete_mute_rule round-trips (skips in the normal unit run). Verified: Darling service + Darling.Tests build clean (0 errors, 0 warnings in the changed source); Darling.Tests 2821 passed / 0 failed / 145 gated-live skipped; Lite.Tests CrossAppMcpToolInventoryPinTests 2 passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Darling MCP: alert-tuning write tools (update_alert_settings, create/delete_mute_rule)
…erver) Add the server-onboarding MCP write tools so an MCP client can stand up or tear down FLEET monitoring conversationally - the service-side twin of the Viewer's Add / Manage Servers dialogs, and the sibling of the #1600 Custom Views and #1608 alert-tuning MCP write tools. - add_servers (BULK): a JSON array of server objects, processed sequentially - validate -> case-folded dedupe (shared ServerIdHelper.BuildStorageName gate, #1549) -> in-process DarlingServerConnector.ProbeAsync (the service holds the network path + credentials, so no test_connect command plane) -> DarlingSecrets DPAPI-encrypt (round-trips at collection) -> INSERT mirroring SeedMonitoredServersAsync. Per-server added/duplicate/connection_failed/invalid; a connection failure does not abort the batch; Entra/MFA rejected; encrypt_mode + trust_server_certificate exposed. Returns {added, skipped, failed, results}. - remove_server: resolve via the same resolver the read tools use, DELETE the config_monitored_servers row. - Grant: mcp role gets INSERT/UPDATE/DELETE on config.config_monitored_servers (provisioning, not migration); the encrypted_password column stays SELECT-carved (write a credential, never read one back). The #1608 config_service beacon column-grant already covers the monitored-servers bump trigger. - MCP instructions (85 -> 87 tools), cross-app ratchet (Darling-only), /api/read write-exclusion, and the README MCP blast-radius (credential-on-the-wire note). Verified: Darling service + Darling.Tests build clean; Darling.Tests 2847 passed / 0 failed / 146 gated-live skipped (DARLING_TEST_PG cleared); Lite.Tests CrossAppMcpToolInventoryPinTests 2 passed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Darling MCP: bulk add/remove monitored servers (add_servers, remove_server)
- Bump all 6 csproj files 3.1.0 -> 3.2.0 (Version/AssemblyVersion/FileVersion; InformationalVersion on the 4 non-Darling) - CHANGELOG: stamp [3.2.0] - 2026-07-21, consolidate duplicate Added/Changed/Fixed sections (lossless), add #1128/#1581 link refs - README sync: Lite collectors 26 -> 36 (+10 rows, fix session_stats cadence), Lite MCP 55 -> 74 (+21 tool rows), ignored-waits 144 -> 124; correct stale Darling-only collector/tab/MCP-tool claims (now shared) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Release v3.2.0
Release v3.2.0
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
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 : )