Skip to content

MCP budget: describe_custom_view_catalog groups measures by source, under the response budget (#4198) - #4272

Merged
erikdarlingdata merged 8 commits into
devfrom
fix/4198-custom-view-catalog-default
Sep 25, 2026
Merged

erikdarlingdata merged 8 commits into
devfrom
fix/4198-custom-view-catalog-default

Conversation

@erikdarlingdata

Copy link
Copy Markdown
Owner

Part of #4198.

Why

describe_custom_view_catalog returned 98,173 bytes at default arguments (measured on both the SQL Server and PostgreSQL-target production stores). This tool reads no store: it is static reference data. It is the Custom Views compose catalog: the measures, dimensions, aggregates, units, and viz vocabulary an author needs to build a valid panel. A naive cut risked hiding a real measure or its legal aggregates.

What changes

  • Default call is now grouped by source (collector table). Each measure keeps only the fields a panel spec names: key, displayName, kind, unitFamily, and validAggregates. validAggregates stays per-measure (not hoisted to the source level) because it varies within a source. Measuring all 179 measures: 9 of 52 sources have more than one distinct validAggregates set. No source varies in allowedDimensions.
  • source (new, optional string): drills into one source's full per-measure detail (category, archetype, native/default unit, default aggregate, allowedDimensions, appliesTo) plus that source's own dimensions. An unmatched name returns empty measures/dimensions and a note pointing back at the default call, not an error. This tool has never returned an error, and a typo returns the same shape a caller parses.
  • full_detail (new, optional bool, default false): returns the complete catalog as before: the same flat {measures, dimensions, annotationSources, universalDimensions, unitFamilies, aggregates, timeBuckets, filterOps, viz} shape, every field. Byte-identical to the pre-fix 98,173 bytes (pinned by test).
  • Everything the compact default drops is reachable. allowedDimensions is dropped from the compact default, not hoisted. It is uniform across every measure of a source (verified for all 179 measures, 52 sources), so source= recovers it. appliesTo gates nothing at compose time: it is a UI greying hint for the web composer (design D4) and never blocked panel-building.
  • The tool's own description explains the default and both opt-ins. The longer explanation moved after the <<GUIDE>> marker (get_tool_guide). The served (tools/list) description stays small.
  • validate_custom_view, create_custom_view, and two other places that point authors at this tool (a custom-alert-rule tool, the MCP system instructions) say only "call describe_custom_view_catalog first". None assert its shape, so none needed a text change.

The web viewer is unaffected

/api/catalog (the Custom Views editor's only catalog fetch, in wwwroot/js/views-api.js) calls DarlingWebEndpoints.BuildCatalogNode() then BuildComposeCatalogNode() directly. It never calls the MCP tool method (describe_custom_view_catalog is in the /api/read exclusion list). The web editor still gets every measure at full detail, unfiltered and ungrouped. BuildComposeCatalogNode() itself is untouched. The new compact/source-filter logic is a pure re-shape of its output, one layer up, in the MCP tool method only.

Extended the existing no-rig Catalog_CarriesTheComposeSection pin in DarlingComposeTests.cs. The assertions confirm /api/catalog's compose section still carries appliesTo, allowedDimensions, and category per measure, with no compact marker.

#4224 (McpReadToolBudgetLiveTests)

This tool is on #4224's ExemptOffenders roster (it has no server/store argument to seed a payload from, so it does not fit that live-store harness). #4224 has not merged and is stalled, so the coordinator lifted the wait for this lane. McpReadToolBudgetLiveTests is not on dev, so this PR does not create or touch it. Whichever of #4224 or this PR merges second must remove describe_custom_view_catalog's row from that roster. It is redundant with the dedicated coverage this PR adds (DarlingMcpCustomViewCatalogSizeTests). The roster file does not exist until #4224 lands.

No Lite twin

Custom Views (and this catalog tool) are Darling-only. Lite has no DescribeCustomViewCatalog or Custom Views MCP surface (confirmed: no match in Lite/Mcp/*.cs). Skipped the common brief's Lite steps and the Lite.Tests full run.

Test plan

Rig: reused the stopped rig-th (port 55983, already UTC), started in the background, confirmed "ready to accept connections". Dropped and recreated darlingtest/probe first (this tool needs no rig itself but the full suite does).

  • dotnet build Darling.Tests, 0 Warning(s), 0 Error(s).
  • Before/after bytes, measured through the tool method itself (UTF-8), pinned in DarlingMcpCustomViewCatalogSizeTests (new file):
  • DarlingMcpCustomViewToolsSurfaceTests: 31 tests, all pass. Includes 5 new or rewritten tests: compact default shape, full_detail reproducing the original shape, source drill-down, unknown source, and a losslessness check. The losslessness check verifies every compact-default measure key is reachable at full detail and every source name is a working filter.
  • McpToolsListBudgetTests: updated DarlingMcpCustomViewTools.txt (measured, not hand-computed) and raised TotalCeilingBytes by the exact measured growth (+472 bytes), with its own change-log line.
  • DarlingComposeTests.Catalog_CarriesTheComposeSection (extended): /api/catalog still serves full per-measure detail. Passes.
  • Full Darling.Tests suite, once, after merging origin/dev and recreating darlingtest: 13,892 total, 0 errors, 0 failed, 47 skipped (pre-existing, env-gated), 1 not-run (same reason).
  • Lite.Tests: not run, no Lite twin exists for this tool (see above).

Rig stopped (pg_ctl stop -m fast) after the run.

CHANGELOG entry

SECTION: Fixed
ENTRY:

Generated with Claude Code

https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ

erikdarlingdata and others added 5 commits September 25, 2026 04:48
…ource (#4198)

Default default-argument call was 98,173 bytes (#4198's own measurement), three
times the tool's 32 KB budget. It is pure static reference data (no server/store
read), so the cut groups the 179 measures by source and keeps only
key/displayName/kind/unitFamily/validAggregates per measure; source=<name>
drills into one source's full detail, full_detail=true returns the original
shape unfiltered. /api/catalog (the web Custom Views editor) calls the
underlying builder directly, never this MCP method, so it is unaffected -
pinned in DarlingComposeTests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
…ld CI

GitHub did not fire pull_request events for this draft-opened PR.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
Merged: dev 172,367 + TC's +472 (describe_custom_view_catalog) = 172,839.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
erikdarlingdata and others added 3 commits September 25, 2026 09:02
…dDimensions, source=<name> returns it

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
…atalog-default

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3
Measured with McpToolsListBudgetTests after merging origin/dev (#4261,
#4258, #4265, #4267, #4264, #4266 and #4268) plus this PR's catalog
changes. Budget, census and tool-guide classes: 219/219.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
@erikdarlingdata
erikdarlingdata enabled auto-merge (squash) September 25, 2026 13:08
@erikdarlingdata
erikdarlingdata merged commit f33169f into dev Sep 25, 2026
15 of 16 checks passed
@erikdarlingdata
erikdarlingdata deleted the fix/4198-custom-view-catalog-default branch September 25, 2026 13:16
erikdarlingdata added a commit that referenced this pull request Sep 25, 2026
Resolves the #4198 train's conflicts after #4272 landed:
- McpToolsListBudgetTests (Darling and Lite): keep every change-log line;
  TotalCeilingBytes re-measured on the merged tree (Darling 174,373,
  Lite 92,041).
- McpPayloadContractCensusTests: query_text_truncated keeps dev's files
  and adds DarlingMcpDataTools.cs for get_query_store_top.
- Lite McpQueryTools: dev's get_query_store_regressions preview constant
  and this branch's get_query_store_top one shared a name in one class;
  the regressions one is now RegressionsQueryTextPreviewLength.
- QueryStoreRegressionsWebDefaultTests: its "no full_text false" check is
  scoped to the regressions dispatch entry, since get_query_store_top's
  web entry keeps full_text off by default on purpose.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
erikdarlingdata added a commit that referenced this pull request Sep 25, 2026
…sclosure

McpToolsListBudgetTests: keep every change-log line. #4231 adds no head
bytes, so TotalCeilingBytes is dev's measured total after #4272 and #4273
(174,373), re-measured on the merged tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
erikdarlingdata added a commit that referenced this pull request Sep 25, 2026
…as merged

After merging dev, the per-tool fixes for get_blocking (#4267),
get_collection_log (#4265), get_query_store_regressions (#4264),
get_collection_health (#4268), describe_custom_view_catalog (#4272) and
get_query_store_top (#4273) are all in, and get_fleet_overview already fit
(CI's stale-exemption message). Every row goes; CI's live run decides.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
erikdarlingdata added a commit that referenced this pull request Sep 25, 2026
…t-read

McpToolsListBudgetTests: keep every change-log line. TotalCeilingBytes
re-measured on the merged tree: dev after #4272 and #4273 (174,373) plus
get_store_host's 616 bytes = 174,989.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
erikdarlingdata added a commit that referenced this pull request Sep 25, 2026
* Add the #4198 MCP read-tool budget pin (part of #4198)

McpReadToolBudgetLiveTests reflects over every [McpServerTool] method
on every [McpServerToolType] class in the Darling service assembly,
excludes write tools/analyze_*/compare_*/audit_config, binds each
tool's DI services and server_name generically, and asserts the reply
stays under McpResponseBudget.DefaultBytes unless the tool is named
in an explicit, byte-stamped exemption roster. A fix lands by
deleting its row.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TszxYhJJbTEh4LrZ56NYo3

* MCP budget pin: empty ExemptOffenders now every #4198 per-tool lane has merged

After merging dev, the per-tool fixes for get_blocking (#4267),
get_collection_log (#4265), get_query_store_regressions (#4264),
get_collection_health (#4268), describe_custom_view_catalog (#4272) and
get_query_store_top (#4273) are all in, and get_fleet_overview already fit
(CI's stale-exemption message). Every row goes; CI's live run decides.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ

* MCP budget pin: get_collection_health is still over on this fixture

CI on 08e6e81 measured get_collection_health at 35,145 B, over the 32 KB
default. #4268 compacts only healthy collectors with nothing to report, and
this fixture's collectors are not healthy, so nothing compacts. The row goes
back, under #4198, which stays open for it. Every other exempt tool fits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
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