Repository navigation
validate_custom_view/run_custom_view_panel move reading guidance off tools/list (#3898) - #4116
Merged
Merged
Conversation
…tools/list (#3898) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QQh8LczP1HGLXQYAx4oTZC
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QQh8LczP1HGLXQYAx4oTZC
…are error (#3898) A bad spec or panel, and a query that fails or times out, return "invalid". Only an unexpected internal fault returns "error". The head listed both words without saying which applies when. Served size goes from 615 to 612. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QQh8LczP1HGLXQYAx4oTZC
erikdarlingdata
marked this pull request as ready for review
September 24, 2026 03:29
erikdarlingdata
enabled auto-merge (squash)
September 24, 2026 03:29
9 tasks done
erikdarlingdata
added a commit
that referenced
this pull request
Sep 24, 2026
* Add 48 buffered CHANGELOG entries in one splice Adds 48 entries and 48 link refs (#4057, #4077, #4079, #4081, #4082, #4083, #4084, #4085, #4086, #4087, #4088, #4089, #4090, #4091, #4092, #4093, #4095, #4096, #4099, #4100, #4101, #4103, #4105, #4106, #4107, #4108, #4109, #4110, #4111, #4113, #4114, #4115, #4116, #4117, #4118, #4119, #4120, #4121, #4122, #4123, #4124, #4125, #4126, #4127, #4131, #4133, #4136, #4141). Each PR's entry was buffered, and this lands every entry whose PR was merged on origin/dev when it ran. Entries found under a bare section line (none unless the old script ran again) move into the matching ### section, below the new entries. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QQh8LczP1HGLXQYAx4oTZC * Changelog splice: add #4137's entry, which merged before the splice but was missed #4137 (pg_plan_capture reads csvlog) merged at 05:57Z with a CHANGELOG entry section in its body. It was neither spliced nor listed as needing no entry. Its entry goes under Fixed, right after #4136's, and #4136's last sentence now points to it instead of saying plan capture is unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NUU29PuGg9TUFBsACgZg2K --------- 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.
Refs #3898.
Why
Issue #3898: a client that loads Darling's whole MCP catalog pays for every tool description before it asks its
first question.
validate_custom_viewandrun_custom_view_panelserved 1,576 and 1,084 characters each,mostly reading guidance rather than facts needed to pick the tool. This moves that guidance off
tools/listandinto
get_tool_guide, so nothing is deleted, but the catalog gets smaller.What changes
Both tools are Darling-only (no Lite twin exists for either name). Each description now carries a short head.
tools/listserves the head, plus aReading guide: get_tool_guide.pointer. The full original text becomesa tail, served only by
get_tool_guide. No tool body, SQL, or parameter was touched.validate_custom_viewrun_custom_view_panelCorrections
None. Every fact in the original descriptions checked out against
DarlingWebEndpoints.ValidateDefinition,RunComposedPanelAsync, andComposeStoreAvailability(notice/row-cap logic).D4 removals
None. Neither description carried an issue reference or an anecdote.
Re-pointed pins
None needed. No existing test pinned a literal sentence from either description. The full suite passed
unmodified after the conversion (see Test plan).
Status routes (the status words the heads state)
validate_custom_viewdoes not use the{status, message}envelope on a normal answer. It returns{valid, error}instead:valid:true/valid:false, error:"..."-DarlingMcpCustomViewTools.cs:119-120, fromDarlingWebEndpoints.ValidateDefinition'sDefinitionValidation.IsValid/.Error.ValidateDefinitionisfail-fast. The first failing check returns, so a
falseanswer never lists a second problem.status:"error"- only from the outercatch (Exception ex)atDarlingMcpCustomViewTools.cs:124(
McpHelpers.FormatError). This is an unhandled exception, not a normal validation miss.run_custom_view_panelhas nostatusfield on a successful answer ({sql, rows, annotations, notice?},DarlingMcpCustomViewTools.cs:283-284). On failure it uses the localOutcome(status, message)envelope:status:"invalid"- a malformed spec JSON (:274) or a non-object body (:279), both inDarlingMcpCustomViewTools.cs. EveryComposeRunOutcome.BadRequest(...)insideRunComposedPanelAsynclands here too. Causes: a missing or doubly-nested panel, bad
variables, a panel that failsComposeSpec.TryParsePanel, or a malformed or oversized absolute window (DarlingWebEndpoints.cs:956-1028).A
PostgresExceptionfrom the bounded query, for example astatement_timeout, also lands here (:1086).All of these surface through
DarlingMcpCustomViewTools.cs:285(
outcome.IsServerError ? "error" : "invalid").status:"error"-ComposeRunOutcome.ServerError(...)atDarlingWebEndpoints.cs:1090, an unexpectedexception during the run rather than a
PostgresException. The outercatchatDarlingMcpCustomViewTools.cs:289(McpHelpers.FormatError) also lands here.notice(present only on a successful payload) -DarlingWebEndpoints.cs:1074-1079sets it whenComposeStoreAvailability.CombineNotices(...)(ComposeStoreAvailability.cs:353-357) returns non-null. Thathappens when
BuildRetentionNotice(partial retention coverage) orBuildRowCapNotice(row cap hit) fires.The key is absent entirely, not null, when neither one does.
D9 traps
{valid:false, error:"unknown key 'filter', did you mean 'filters'?"}.After renaming the key, is the definition now guaranteed valid?
Correct: Not necessarily. The error names only the first problem found, so fixing it can surface another
one underneath.
Prevents it: "naming only the FIRST problem found; fixing it can reveal more."
aggregatinstead ofaggregate. Does validate_custom_viewaccept the definition and just skip that field as if it were absent?
Correct: No. Unknown keys are errors at every level (root, panel, cell, filter, overlay). A stray key is
never silently dropped.
Prevents it: "Unknown keys are ERRORS at every level (root, panel, cell, filter, overlay), never silently
dropped."
stored copy?
Correct: No. It is a dry run. Nothing is persisted regardless of the result.
Prevents it: "WITHOUT persisting anything."
source,measure, and soon) nest inside a
panelkey on the cell, the way run_custom_view_panel's top-level spec nests?Correct: No. A notebook cell is flat. Its keys sit directly on the cell object. Only
run_custom_view_panel's own spec nests under
panel.Prevents it: "A notebook cell is FLAT (carries the panel's own keys directly); only
run_custom_view_panel's spec nests under 'panel'."
{"sql": "...", "rows": [...], "annotations": [...]}. Does confirmingsuccess require checking a
statusfield?Correct: No. There is no status field at all on success. status appears only on failure.
Prevents it: "with no 'status' field on success."
status:"error"?Correct: No. A bad spec is
status:"invalid", not"error". So is a query that fails or times out."error"is only for an unexpected internal fault.Prevents it: "Failures return {status, message}: "invalid" for a bad spec or panel, or a failed or
timed-out query; "error" for an internal fault."
that?
Correct: Yes. run_custom_view_panel also executes the compiled query, and that can still fail, for
example on a timeout. That returns
status:"invalid", and validation alone never catches it.Prevents it: "Failures return {status, message}: "invalid" for a bad spec or panel, or a failed or
timed-out query."
noticefield. Is part of the requested window still hidden by the store'sretention?
Correct: No. An absent notice specifically means neither a retention gap nor a row cap applied to this
result.
Prevents it: "absent means neither happened."
notice. Does that mean the query failed?Correct: No. notice rides on a successful payload, and the rows are still real data. It flags a partial
window or a truncated row count, not a failure.
Prevents it: "with no 'status' field on success" (notice only ever appears on that same success shape).
hoursentirely and gives no window at all. What window does run_custom_view_paneluse?
Correct: The last 24 hours ending now, not an unbounded or all-time query.
Prevents it: "Window ends now: 'hours' (default 24)."
hours:6andwindowStart/windowEnd. Which one does run_custom_view_panelhonor?
Correct: The absolute
windowStart/windowEndpair, nothours.Prevents it: "unless ISO-8601 'windowStart'+'windowEnd' win instead."
serverkey is sent. Does run_custom_view_panel default to one particular server, or refuse thecall?
Correct: Neither. An omitted (or
"All") server runs the whole fleet.Prevents it: "'server' omitted or "All" runs the whole fleet."
Test plan
dotnet build Darling/Darling.Tests/Darling.Tests.csproj -c Debug: Build succeeded, 0 Warning(s), 0Error(s).
McpToolGuide*,McpToolsListBudget*,McpDescription*,McpZeroIsAMeasurement*,McpPayloadContractCensus*- Total: 203, Failed: 0, Skipped: 4.DarlingComposeTestsand its 4 live-PostgreSQL classes,DarlingMcpCustomViewToolsSurfaceTests,DarlingMcpCustomViewToolsLivePostgresTests,DarlingWebEndpointsTests,McpPayloadContractCensusTests, andMcpReadCommandTimeoutTests. Total: 491,Failed: 0, Skipped: 6 (live PostgreSQL, no rig in this lane).
McpToolGuideHeadsCustomViewTestsfailed, restored, rebuilt, confirmed green again.python .../3898-d9/dropcheck.py origin/dev HEAD validate_custom_view run_custom_view_panel:validate_custom_view [Darling] old=1576 new=2117 sentences=8 missing=0.run_custom_view_panel [Darling] old=1084 new=1679 sentences=5 missing=0.git merge origin/dev(clean, no conflicts), then fullDarling.Testssuite once:Total: 13337, Errors: 0, Failed: 0, Skipped: 636, Not Run: 1. No
DarlingInstallLocationTestsfailures (thebrief's two known ones): DarlingInstallLocationTests: the #4052 checks pass when run non-elevated #4111 landed on dev during this merge and all 28 tests in that class pass now.
Coordinator verification
run_custom_view_panelhead. It said a failure returns "invalid" or "error" but not whichone applies when. A D9 reader then said a bad spec returns "error". The code returns "invalid" for a bad spec
or panel and for a query that fails or times out (
IsServerErroris false for aPostgresException). Itreturns "error" only for an unexpected internal fault. The head now says so. The lane's own D9 answer on this
trap called a failed query "error", which the fix also corrects.
size went from 615 to 612. The budget line, the cap constant and the pin in
McpToolGuideHeads.CustomView.csmatch.validate_custom_viewis correct as written.McpToolGuide*,DarlingComposeTests,DarlingMcpCustomViewToolsSurfaceTests,DarlingWebEndpointsTests, the censuses,McpReadCommandTimeoutTests,McpZeroIsAMeasurementTests): 628 of 628.Handoff
Nothing deferred. Both tools in this lane's scope (
validate_custom_view,run_custom_view_panel) are fullyconverted and green.
update_custom_viewwas left alone per the brief (under the served-size floor).🤖 Generated with Claude Code
https://claude.ai/code/session_01QQh8LczP1HGLXQYAx4oTZC