Repository navigation
MCP budget: get_plan_corrections defaults sized to the shared response budget (#4198) - #4257
Merged
Merged
Conversation
…#4198) A default call measured 95,428 bytes on a busy production server, over 3x the 32 KB shared budget, because 50 rows each carried query_text truncated only at 2,000 characters. Preview it at 150 chars with a query_text_truncated flag and a full_text opt-in, and cut the default row limit to 25 to match the row's own width once query_text is thin. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
…fault cut (#4257) get_plan_corrections's new full_text MCP default (false) previews query_text at 150 characters. 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_text to true so the viewer keeps showing the whole query text, and add a source-text pin so a future edit that drops the argument fails a test instead of silently truncating what the viewer renders. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
Darling McpToolsListBudgetTests: 171_637 + 137 (plan_corrections) + 82 (audit_config) + 364 (deadlock_detail) = 172_220. Lite: 89_881 + 137 + 253 = 90_271. McpPayloadContractCensusTests: keep dev's FieldPreviewCutKeys description, add both deadlock_graph_xml_truncated and query_text_truncated. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
erikdarlingdata
marked this pull request as ready for review
September 25, 2026 08:05
erikdarlingdata
added a commit
that referenced
this pull request
Sep 25, 2026
Incorporates plan_corrections (+137 Darling/Lite) from dev (#4257). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
This was referenced Sep 25, 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.
Part of #4198.
Why
get_plan_correctionsat default arguments measured 95,428 bytes on a busy production server (24h window,limit=50). That is over 3x the shared 32 KB MCP response budget (McpResponseBudget.DefaultBytes). The default page fetched 51 rows and truncated each row'squery_textonly at 2,000 characters.A synthetic reproduction on this lane's rig confirms the shape. It seeded 51 rows across five query-text
lengths, from 100 to 4,600 characters. Most rows were Active with null action fields. One row in five was
acted on. That measured 129,359 bytes at the old defaults. The exact number depends on the seeded
population, but the order of magnitude matches.
The row itself is wide independent of
query_text: 20+ named fields, four lifecycle timestamps, several free-text reason columns. Cutting only the text preview was not enough to clear the budget. So the default row limit is cut too, the same way #4198 cutget_query_store_regressionsfrom 20 rows to about 5 for a similarly wide row.What changes
Both products (
DarlingMcpPlanCorrectionTools.cs,McpPlanCorrectionTools.cs), identically:query_textis now previewed at 150 characters by default, was 2,000. A new per-rowquery_text_truncatedflag istrueonly when that row's text actually exceeded the preview length.full_textopt-in parameter, defaultfalse, matchesget_store_query_stats's existing shape. Passfull_text=trueto get every row's wholequery_textback, uncut.limitdrops from 50 to 25.full_text/query_text_truncatedbehavior is documented in the<<GUIDE>>tail instead.get_tool_guideserves that tail, and it does not count against thetools/listbudget.This PR also carries three mechanical fixes the change above required, in files it already touches:
DarlingMcpPlanCorrectionToolsTests.ParamContract_StandardWindowedShape_ServerNameOptionalupdated for the newfull_textparameter.McpPayloadContractCensusTests: added a new roster,FieldPreviewCutKeys, for the<field>_truncatedshape this fix introduces. That is a wide field's own preview cut. It is distinct from a page cut (row
count), a second bound, or a source-side (collector-time) cut. The full value is in the store. The flag
is actionable: pass
full_text=trueand get it back. Classifiedquery_text_truncatedinto it on bothfiles.
McpToolsListBudgetTests(both products): updated theDarlingMcpPlanCorrectionTools/McpPlanCorrectionToolsblocks for the new
full_textparameter line. RaisedTotalCeilingBytesby the measured +137 bytes oneach product's full
tools/listpayload. Darling went from 171,637 to 171,774. Lite went from 89,881 to90,018. A change-log line is above each constant.
/api/readrow forget_plan_correctionsinDarlingWebEndpoints.csnow pins its ownfull_textdefault totrue. That is the opposite of the MCP signature'sfalse. This keeps this PR'sMCP-side preview default from silently truncating the query text the viewer renders. The row already kept
limitat the viewer's own 50, unaffected by the MCP default dropping to 25. The matching/api/catalogrow gained a
full_textparameter declaration. The viewer'sserver-tabs.jspanel passes its ownlimit: 50but nofull_text, so the row's default governs. A new pin,PlanCorrectionsWebDefaultTests,reads the row's own dispatch line and fails if
full_textstops being passed astrue. Lite parity:confirmed by grep that no Lite UI code calls
McpPlanCorrectionTools.GetPlanCorrectionsdirectly. Lite'sUI reads
LocalDataService, not the MCP tools, so this default change does not reach Lite's UI at all.Test plan
Darling/Darling.Tests/PlanCorrectionBudgetLiveTests.cs. Its own file, its own seeding, not extending a shared seeder. Seeds 51 rows across fivequery_textlengths (100/2200/2800/3600/4600 chars) with realistic field sparsity. Asserts the default call is underMcpResponseBudget.DefaultBytes. Asserts bothquery_text_truncated=trueand=falserows appear on the default page. Assertsfull_text=truereturns the newest row's wholequery_textuncut. Measured before the fix (temporarily reverting the tool file, same seed): 129,359 bytes. After the fix: 29,075 bytes, 11% headroom under the 32,768-byte budget. Ran alone: pass.Lite.Tests/PlanCorrectionBudgetTests.cs(DuckDB, no rig needed). Same shape and assertions as the Darling live test. Ran alone: pass.Darling.Tests:DarlingMcpPlanCorrectionToolsTests,PlanCorrectionFrameLiveTests,DarlingPlanCorrectionMigrationTests,DarlingPlanCorrectionLiveMigrationTests,PlanCorrectionBudgetLiveTests, 15 tests, pass.McpToolsListBudgetTests, 5 tests, pass.McpPayloadContractCensusTestsplusMcpToolGuideHeadsSqlTailPlanCorrectionsTests, 70 tests, pass.Lite.Tests:McpPageContractTests,McpToolsListBudgetTests,McpToolGuideHeadsSqlTailPlanCorrectionsTests,PlanCorrectionBudgetTests, 30 tests, pass.origin/dev: fast-forward, no conflicts with this lane's files. Field data confirms the interval-table fix removes the spill, ship it (#3953) #4208 had not landed at merge time and did not touchplan_correctionfiles in what merged.Darling.Testssuite, once, against this lane's rig (UTC, port 55978): 13,844 total, 48 failed, 1 errored, 47 skipped, 666.7s. None of the 48 failures are in a file this PR touches, and none areget_plan_corrections/plan_correction-related. They cluster inPayloadDimensionLiveTests,TimescaleAggregateCompressionTests, several*AgainstDevPostgres-suffixed classes, and oneTrendPayloadBudgetLiveTestsstream-read exception. All look environment-related: this rig has noDARLING_TEST_PG_TARGETsecond Postgres instance configured, which several of those classes need. I did not cross-check these against dev's own latest CI run. The coordinator needs to do that before treating them as pre-existing.Lite.Testssuite, once: 5,338 total, 0 failed, 0 errors, 279.6s. Clean.Darling.Tests, filtered to every class that readsDarlingWebEndpoints.cs(55 classes, includingDarlingWebEndpointsTestsandServerPageTabsTests).Also filtered to
PlanCorrectionsWebDefaultTests,McpToolsListBudgetTestsandMcpPayloadContractCensusTests. Result: 1,434 total, 0 failed, 31 skipped (live classes, no rig for thisupdate). Proved the new pin fails by reverting the
full_textargument alone: 1 run, 1 failed,Assert.Containson the missing substring. Restored the fix and reran the full filtered set green.CHANGELOG entry
SECTION: Fixed
ENTRY:
get_plan_correctionsdefault call stays under the MCP response budget ([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]): A default call returned nearly 100 KB on a busy server. Each row carries 20+ fields and the query text ran to 2,000 characters. The text preview is now 150 characters. Each row gets aquery_text_truncatedflag and afull_textopt-in. The default row limit dropped from 50 to 25.REF:
[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]: 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
For the coordinator
Darling.Testsfull-suite failures against dev's latest CI Build run before treating them as pre-existing. I ran out of context budget to do that cross-check myself. None are in files this PR touches.Lite.Testsrun finished clean after my first report: 5,338 total, 0 failed.<<GUIDE>>, head sentence about the new preview afterMcpToolGuideHeadsSqlTailPlanCorrectionsTestspinned that head at a 620-character target. The explanation lives in the<<GUIDE>>tail instead. That keeps the served head unchanged and saves tools/list bytes versus my first pass.Generated with Claude Code
https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3