Skip to content

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

Closed
erikdarlingdata wants to merge 3 commits into
devfrom
fix/4198-custom-view-catalog-default
Closed

erikdarlingdata wants to merge 3 commits into
devfrom
fix/4198-custom-view-catalog-default

Conversation

@erikdarlingdata

@erikdarlingdata erikdarlingdata commented Sep 25, 2026 •

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

…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
@erikdarlingdata erikdarlingdata changed the title DO NOT MERGE (MCP budget): describe_custom_view_catalog groups measures by source, under the response budget (#4198) MCP budget: describe_custom_view_catalog groups measures by source, under the response budget (#4198) Sep 25, 2026
@erikdarlingdata
erikdarlingdata marked this pull request as ready for review September 25, 2026 09:44
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVjn4PBJN71NQXdFo6ZxNQ
@erikdarlingdata

Copy link
Copy Markdown
Owner Author

Closing to retrigger Build workflow CI (draft PR never triggered it on open)

…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
@erikdarlingdata

Copy link
Copy Markdown
Owner Author

Re-creating as non-draft to fix missing Build CI (see PR history for context)

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