Show render tag warnings alongside query results#889
Merged
Conversation
Every query response already carries `renderLogs`, the render tag validation findings for that result, and the MCP execute_query tool already reports them. Nothing in the UI read them, so a misconfigured tag produced a broken chart with no explanation: the only way to find out was the network tab. Surface them as a non-blocking note over the result. Severity describes the tag defect rather than whether the chart drew, so a finding is never used to withhold a result: an error-severity tag still renders, and a warning can still blank a chart. Annotating is correct in both directions; withholding is not. The note is a button rather than a bare icon so the message is reachable by keyboard and exposed to a screen reader, and carries the same translucent backdrop as the sibling overlays in ModelCell and NotebookCell. Callers that execute a query pass their findings through. Notebook and workbook cells render a stored result whose response has no renderLogs, so they have none to pass and the prop stays optional. Signed-off-by: Monty Lennie <[email protected]>
kylenesbit
approved these changes
Jul 19, 2026
kylenesbit
left a comment
Collaborator
There was a problem hiding this comment.
Approve. The annotate-don't-withhold decision is correct given severity describes the tag defect and doesn't predict whether the chart drew. The overlay avoids the measured-height feedback loop, summarizeRenderLogs is a pure and well-tested helper, and the prop plumbing is complete with honest scoping (Notebook/Workbook cells correctly omitted since their result has no renderLogs).
Optional nits only, none blocking:
- Consider MUI's
Warning/Erroricons instead of a coloredInfoOutlinedglyph (also more consistent with the large-result overlay in this same file). summarizeRenderLogsruns before the early returns; moving it below (oruseMemo) is marginally cleaner.- Confirm
bun:testmatches the SDK's test-runner convention.
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.
What
Every query response already carries
renderLogs— the render tag validation findings for that result — and has since #635. It's inapi-doc.yaml, in all four generated clients, and the MCPexecute_querytool already reports it, so an AI agent gets told when a tag is wrong. Nothing in the UI ever read it, so a human got a broken chart and no explanation. The only way to find out was the network tab, which is exactly how this surfaced: a user hit a blank chart and had to open devtools to discover the renderer had been telling us the whole time.This surfaces those findings as a non-blocking note over the result.
Above: a bad tag renders a blank chart, now with the reason attached. Below it, a clean query, no note.
Design: annotate, never withhold
Severity describes the tag defect, not whether the chart drew, and it fails to predict the render in both directions. The case that prompted this was
severity: "warn"and produced a blank chart. Meanwhile a benign warning can accompany a perfectly good chart, anderror-severity findings coexist with a drawn result —model.tsnotes they affect "only how a field renders, never whether the model compiles or a query runs".So any rule that used severity to withhold a result would be guessing, and wrong either way: it would blank charts the renderer is actively drawing, replacing a visible result with nothing. Annotating is wrong in neither direction. A blank chart plus a note is recoverable — the user reads it and fixes the tag. A withheld good chart is not.
This also keeps faith with #861, which deliberately made render findings non-fatal after the fatal treatment caused package-load failures and a control-plane retry loop.
debugandinfoare dropped; onlywarnanderrorare worth a user's attention.Shape
ResultContainertakes an optionalrenderLogs?: LogMessage[].summarizeRenderLogs(a pure helper, unit tested) filters to warn/error entries that have a message, dedupes them, and picks the worst severity — everyLogMessagefield is optional in the generated client, so entries without a severity or message are dropped rather than rendered as an empty tooltip.The note is an overlay, not a sibling.
ResultContainermeasuresrenderedHeightand feeds it toRenderedResult, so a block-level element would change the height it just measured and shift every embedding surface.It's a button rather than a bare icon for two reasons. MUI's
SvgIconrendersfocusable="false"andaria-hidden="true", so a bare icon can't take focus and never reaches the accessibility tree — the tooltip is the only channel for this message, so a keyboard or screen-reader user would get nothing at all. And it carries the same translucent backdrop as the sibling overlays inModelCellandNotebookCell; the comment atNotebookCell.tsx:463-470records why ("the white-on-white made it invisible").QueryResult,ModelCellandResultsDialogexecute queries and pass their findings through.NotebookCellandMutableCellrender a storedcell.resultfromexecuteNotebookCell, whoseNotebookCellResultschema has norenderLogs, so they have nothing to pass and the prop stays optional.Not covered
renderLogstoNotebookCellResultand regenerating the clients — a bigger change, happy to do it separately if you want it.SourcesExplorer) renders through@malloydata/malloy-explorer's ownResultPanelrather thanResultContainer, so this doesn't reach it.Tests
Six unit tests on the summarizer (
bun test, 70 pass), covering the real warning payload, worst-severity selection, dropping debug/info, dropping entries with missing optional fields, and dedupe.Verified live against a package with a deliberately bad tag: the wire returned
severity: "warn","Unknown render tag 'viz.stack.y' on field 'root'"; the note appeared with that exact text; a clean query in the same model produced no note.Two traps for anyone adding a Playwright test later.
svg[data-testid="InfoOutlinedIcon"]matches nothing in a production build, since@mui/icons-materialonly emitsdata-testidwhenNODE_ENV !== "production"— locate by role and accessible name instead. And assert keyboard reachability with a realkeyboard.press("Tab"), notlocator.focus(): MUI's Tooltip gates its focus listener on:focus-visible, which programmatic focus doesn't set, sofocus()looks like a failure when the behaviour is correct.