Repository navigation
MCP budget: preview the deadlock graph XML by default on get_deadlock_detail (#4198) - #4254
Merged
Merged
Conversation
…graph on request (#4198) deadlock_graph_xml is the wide field on get_deadlock_detail: a busy production store's default call measured 120,454 bytes for 3 graphs (about 40 KB/graph), over the shared 32 KB MCP response-size budget. Truncates it to a 2000-character preview by default (deadlock_graph_xml_truncated: true), with a full_graph opt-in for the whole XML, the same preview-plus-opt-in shape get_store_query_stats uses for full_text. A dedup_key call (naming one incident) always gets the whole graph, since the caller already paid the cost of naming it. Same fix on Lite's get_deadlock_detail twin (no dedup_key there). Adds a new Darling live test class seeding wide graphs against Postgres, measuring the default call's UTF-8 bytes under the budget; adds a Lite.Tests case doing the same against DuckDB. Updates both products' tools/list budget pins for the new full_graph parameter and the changed tool description. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
get_deadlock_detail's new field-level preview flag needed a class: not a page cut (truncated), not a second bound, not a source-side (collector-time) cut, and not a homonym. Adds FieldPreviewCutKeys for #4198's shape — one wide field previewed under the response budget, with a caller opt-in (full_graph, or a dedup_key call) that gets the whole field back, unlike a source-side cut the caller can do nothing about. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
erikdarlingdata
marked this pull request as ready for review
September 25, 2026 07:11
erikdarlingdata
enabled auto-merge (squash)
September 25, 2026 07:11
…seline to 171_719 171_637 + 82 (#4206) + 364 (#4254) = 172_083 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
erikdarlingdata
disabled auto-merge
September 25, 2026 07:30
…4254) get_deadlock_detail's new full_graph MCP default (false) previews the graph XML. The web viewer's /api/read row calls the same MCP method, so without its own default it would inherit the preview. Pin the row's full_graph to true so the viewer keeps showing the whole graph, and add a source-text pin so a future edit that drops the argument fails a test instead of silently shrinking what the viewer renders. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
11 of 13 tasks
erikdarlingdata
added a commit
that referenced
this pull request
Sep 25, 2026
Classified the four new payload keys (findings_truncated, findings_truncated_note, confidence_basis_truncated, advice_truncated) in McpPayloadContractCensusTests: findings_truncated/_note join SecondBoundCutKeys/CutNoteKeys as a second, independent page cut beside the tool's pre-existing truncated/truncation_note; confidence_basis_ truncated/advice_truncated start a new FieldPreviewCutKeys roster (added with the same name and tuple shape #4254 uses for get_deadlock_detail, so a later merge only needs to combine array entries). Updated both products' McpToolsListBudgetTests pins for the grown tool: the served head (610 -> 740 bytes, from the new head sentence), the two new parameter lines (limit 122, full_text 146), and each product's TotalCeilingBytes raised by the measured +495 bytes, with a change-log comment. Both products' McpToolsListBudgetTests classes pass (5/5 each). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
erikdarlingdata
enabled auto-merge (squash)
September 25, 2026 08:02
erikdarlingdata
added a commit
that referenced
this pull request
Sep 25, 2026
…ews (#4198) (#4266) * WIP (#4198): get_analysis_findings default limit and text previews Checkpoint of lane TG's uncommitted work at its 200-turn stop. Not yet built or tested as a whole; a finishing lane completes it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3 * #4198: shorten get_analysis_findings' limit description, fix web viewer row Both build now. The limit parameter description was 225 characters, over the D2 200-char cap for a converted tool's parameter; cut it to the essentials and moved the longer explanation into the tool's guide tail (after <<GUIDE>>), on both products. Also fixed a missing space the checkpoint's head-sentence insertion left ("whole.confidence_basis"). The /api/read row for get_analysis_findings inherited the new limit:18/ full_text:false defaults, which would have shown the web viewer's two "Analysis Findings" tables only 18 of a window's chains. Pass Rows(c, "limit", MaxRowLimit) and QueryBool(c, "full_text", true) so the row keeps returning what dev always did: every chain, full text. Added a no-rig source-scan pin (DarlingWebEndpointsTests) that fails if the row regresses, since GetAnalysisFindings needs a live Postgres connection and can't be pinned by invoking it directly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3 * #4198: census and tools/list budget pins for get_analysis_findings Classified the four new payload keys (findings_truncated, findings_truncated_note, confidence_basis_truncated, advice_truncated) in McpPayloadContractCensusTests: findings_truncated/_note join SecondBoundCutKeys/CutNoteKeys as a second, independent page cut beside the tool's pre-existing truncated/truncation_note; confidence_basis_ truncated/advice_truncated start a new FieldPreviewCutKeys roster (added with the same name and tuple shape #4254 uses for get_deadlock_detail, so a later merge only needs to combine array entries). Updated both products' McpToolsListBudgetTests pins for the grown tool: the served head (610 -> 740 bytes, from the new head sentence), the two new parameter lines (limit 122, full_text 146), and each product's TotalCeilingBytes raised by the measured +495 bytes, with a change-log comment. Both products' McpToolsListBudgetTests classes pass (5/5 each). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3 * #4198: drop the head-sentence insertion, bank the pin savings Lite's full suite caught a hard 620-char served-head cap (McpToolGuideTests.EveryConvertedHead_StaysAtOrUnder620Characters and its SqlCore sibling) that McpToolsListBudgetTests' looser 1000-char/ 600-target check didn't. TG's head-sentence addition ("Default limit 18 chains...") pushed the served head to 740; that fact isn't in either guide's required guardrail roster (McpToolGuideHeads.SqlCore.cs), and it's now covered in the tail I added in the prior commit, so the sentence is dropped from the head entirely rather than trimmed. The head is back to its exact original text (610 served bytes on both products). Banked the resulting savings in both products' pins: the per-tool line back to 610, and TotalCeilingBytes lowered to the newly measured total (the two new parameters still cost real bytes: +364 Darling, +353 Lite). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3 * fix CS0102: remove duplicate FieldPreviewCutKeys, add top_query_text_truncated Conflict resolution for McpPayloadContractCensusTests.cs added a second FieldPreviewCutKeys array after SourceSideCutKeys. The branch already defined FieldPreviewCutKeys before SourceSideCutKeys, so the result was a CS0102 duplicate-field error. Remove the second block and add the missing top_query_text_truncated entry to the first array instead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ * Fix Census doc comment run break: remove blank line between items A blank line introduced during merge resolution broke the doc comment XML run between the FieldPreviewCutKeys item and the WithheldSummaryKeys item, causing DocCommentHygieneTests.EveryDocRunClosesTheSummariesItOpens to fail. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3 --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
Part of #4198.
Why
get_deadlock_detailhad no default response-size budget.deadlock_graph_xmlis the wide field. On a busy production store, one lane member measured a default call (limit 5, hours_back 24) at 120,454 bytes and 247 ms. Only 3 deadlocks in the window carried a graph, and each graph averaged about 40 KB. That is almost 4 times the shared 32 KBMcpResponseBudget.DefaultBytestarget from #4198's ruling.What changes
Darling (
Darling/PerformanceMonitor.Darling.Service/Mcp/DarlingMcpBlockingTools.cs) and Lite (Lite/Mcp/McpBlockingTools.cs),get_deadlock_detailonly.get_blockinglives in the same Darling file. It is a different lane's work, and it is untouched here.deadlock_graph_xmlis now a 2000-character preview by default, with a newdeadlock_graph_xml_truncated: truefield alongside it when a graph was cut. This is the same preview-plus-opt-in shapeget_store_query_statsalready uses forfull_text.full_graphargument (defaultfalse) opts back into the whole XML for every row.dedup_keycall (naming one incident) always gets the whole graph for the matched row(s), regardless offull_graph. The caller already paid the cost of naming it, so a preview would defeat the point of the call. Lite'sget_deadlock_detailhas nodedup_key, so this rule only applies on Darling.tools/listbudget pins (McpToolsListBudget/*.cs) moved to match the new served bytes, with a change-log line on eachTotalCeilingBytesbump: Darling +364 bytes (172,001), Lite +253 bytes (90,134). The two differ because Darling's description also covers thededup_keyexemption, which Lite has nothing to exempt.McpPayloadContractCensusTests) gained a newFieldPreviewCutKeysclass.deadlock_graph_xml_truncatedis not a page cut, a second bound, a source-side (collector-time) cut, or a homonym. It is a new MCP read tools have no default response-size budget: at default arguments 12 tools return >50 KB and 3 return >100 KB for one server, more than an agent client's per-result cap #4198 shape: a field-level response-budget preview with a caller opt-in. Future*_truncatedfields of this shape, on other tools' own lanes, will want the same class./api/readrow forget_deadlock_detailinDarlingWebEndpoints.csnow pins its ownfull_graphdefault totrue. That is the opposite of the MCP signature'sfalse. This keeps this PR's MCP-side preview default from silently shrinking what the viewer renders. The matching/api/catalogrow gained afull_graphparameter declaration. Neitherserver-tabs.jsnorview-templates.jspasses its ownfull_graphvalue for this read, so the row's default governs. A new pin,DeadlockDetailWebDefaultTests, reads the row's source text and fails iffull_graphstops being passed astrue.McpBlockingTools.GetDeadlockDetaildirectly. Lite's UI readsLocalDataService, not the MCP tools, so this default change does not reach Lite's UI at all.Test plan
Measured on a new live test seeding 5 planted graphs near 42,221 characters each, the worst realistic default page. Production's 3 real graphs averaged about 40 KB each.
New tests:
Darling/Darling.Tests/DarlingMcpDeadlockDetailBudgetLiveTests.cs(new file). Plants 5 wide graphs against Postgres. Asserts the default call is under budget and each row is marked truncated. Assertsfull_graph: truereturns the whole XML unmarked. Asserts adedup_keycall returns the whole XML even withfull_graph: false.Lite.Tests/McpPageContractTests.cs: addedGetDeadlockDetail_Default_StaysUnderResponseBudget_WithFiveWideGraphs, same shape against DuckDB (nodedup_keyon Lite).Suite runs:
origin/dev: 13,838 total, 47 skipped, 1 not run, 3 failed. One was this change's own census gate (McpPayloadContractCensusTests.EveryCutKey_IsThePageDialect_OrClassified_OnBothSkus), fixed and reverified green in isolation (68/68). The other two are unrelated to this diff. They reproduce in isolation on a fresh rig, not merely under full-suite load:TrendPayloadBudgetLiveTests.EveryDefaultAnswer_StaysNearTheBudget_AndTheLargestAnswerStaysUnderTheCapfails withget_file_io_trendreturning a stream-read exception, not a data assertion. Different tool, no code path this PR touches.PgTargetBlockingTests.ThirtyOneDaysOfLightBlocking_...fails an anomaly-detection ratio assertion (2.7692 vs an expected 2.8-3.0 range), in a scenario anchored toDateTime.UtcNow, so it is date/time-of-run sensitive. Different subsystem (blocking-stats anomaly detection, not deadlock graphs), no code path this PR touches.Darling.Tests, filtered toDeadlockDetailWebDefaultTests,DarlingWebEndpointsTests,ServerPageTabsTests,McpToolsListBudgetTests,McpPayloadContractCensusTests: 160 total, 0 failed. Proved the new pin fails by reverting thefull_graphargument alone: 1 run, 1 failed,Assert.Containson the missing substring. Then restored the fix and reran green. No rig was available for this update. No live class ran, and none of the filtered classes needs one.CHANGELOG entry
SECTION: Fixed
ENTRY:
get_deadlock_detailno longer returns oversized deadlock graphs by default ([MCP budget: preview the deadlock graph XML by default on get_deadlock_detail (#4198) #4254]) - The tool'sdeadlock_graph_xmlfield could push a default call past 100 KB, because each graph runs tens of kilobytes and the tool did not cap that field's size. It now previews each graph to 2000 characters by default and marks itdeadlock_graph_xml_truncated: true. A newfull_graphargument returns the whole graph. Adedup_keycall, naming one incident, always returns it in full.REF:
[MCP budget: preview the deadlock graph XML by default on get_deadlock_detail (#4198) #4254]: MCP budget: preview the deadlock graph XML by default on get_deadlock_detail (#4198) #4254
Generated with Claude Code
https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3