Skip to content

feat(interactions): admission and validation of chart interactions - #127

Open
xavier (xavier-shaw) wants to merge 10 commits into
feat/interactive-apifrom
feat/interaction-admission
Open

xavier (xavier-shaw) wants to merge 10 commits into
feat/interactive-apifrom
feat/interaction-admission

Conversation

@xavier-shaw

@xavier-shaw xavier (xavier-shaw) commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

Each Vega-Lite chart type declares the interaction capabilities it offers, each preset declares the capabilities it needs, and admission matches the two. The same declaration feeds validateChart(), the MCP tools, the docs, and a coverage view, so the list an agent reads and the list the mount enforces come from one place. Hosts then mount from interaction_spec: the MCP chart view, the site editor, and the gallery.

Stacked on #124. Design document: docs/design-interactions.md (with a zh-CN mirror).

Why

A probe over nine chart types showed the old inferred rules admitted click-highlight, brush-x, select, legend-toggle, drag-reorder, axis-highlight, and inspect-index on every one of them, KPI Card and Pie Chart included. Every template defines semanticInteractions, so the "element semantics" test was always true, and the registry's requires was never read.

Commits

  1. contract — eight capabilities in core (elements, cartesian-region, angular-region, navigation, reorder, legend, discrete-axis, index), ChartInteractionSupport, requirements as a list, wrappers stamp preset on their definitions.
  2. templates — all 36 chart types declare an interactionSupport block; navigation, reorder, and supportedRegionGestures fold into it. The design doc's appendix holds the declaration table, generated from the templates.
  3. enforcement — the assembler confirms the data-dependent capabilities against the encodings and writes the active list; admission is one match rule with messages that name the chart type and the missing property. Code throws, spec drops.
  4. discoveryINTERACTION_PRESET_REQUIREMENTS, supportedInteractionPresets(), and a Coverage tab in the Interactions lab.
  5. validationvalidateChart() reports the same warnings; the MCP schema gains interaction_spec; list_chart_types returns interactions per chart type.
  6. docsdocs/interaction-spec.md (en, zh-CN), API reference, chart-author skill, generated Vega-Lite reference.
  7. hosts — the MCP chart view mounts interactively when the spec lists interactions; InteractiveVegaLiteView for the editor and TripleChart; an Interactive bar editor example; two demos moved to the spec.

Behaviour changes

  • ChartTemplateDef.navigation and .reorder moved into interactionSupport, with supportedRegionGestures.
  • a factory call the chart cannot honour now throws at mount where it used to mount and do nothing, for example legendToggle() on a chart with no discrete legend, or a brush on a KPI card.
  • listInteractionPresets().requires is a list, and the capability element-semantics is now elements.

Verification

  • Library: 73 test files, 1635 tests pass. MCP: 7 files, 86 tests. Lint: 0 errors. Typechecks for flint-js, the site, and the MCP UI pass; the declaration build passes; the MCP UI bundle builds.
  • Lab survey with the match rule on: 787 cards, 0 differences between the code tab and the spec tab. The KPI card is the only chart that drops the region presets.
  • Coverage tab: 36 chart types × 20 presets.

🤖 Generated with Claude Code

…s as a list

Eight chart capabilities (elements, cartesian-region, angular-region, navigation,
reorder, legend, discrete-axis, index) move to core as INTERACTION_CAPABILITIES, and
ChartInteractionSupport describes what a chart type offers; ChartTemplateDef gains an
optional interactions block for it. Each registry entry lists the capabilities its preset
needs in requires, and every wrapper stamps preset on the definition it returns so a
definition made in code can be checked against the same list as a spec entry. Nothing
reads the declarations yet.
…pport

The interactions block on ChartTemplateDef replaces the navigation and reorder fields and
the supportedRegionGestures entry of semanticInteractions. All 36 chart types declare
what they offer: marks that resolve to data, the drag regions, the navigable and
reorderable axes, the legend, the discrete axis labels, and the index axis. The assembler
reads the block for navigation axes, reorder axes, and region gestures, so the compiled
facts are unchanged; a test asserts that every template carries the block. The design doc
records the table with the source of each cell and the judgment calls open for review.
… the chart's capabilities

The assembler confirms the declared capabilities against the bound encodings and writes
the active list, with the chart type, into _interactionSemantics. Admission replaces its
four inferred checks with one rule: every capability in the preset's requires list must be
present, or a spec entry drops with a message that names the chart type and the missing
property, and a code definition throws. A plan the assembler did not annotate is read the
way the compile step read it, so hand-built plans keep their behaviour. The region
capability covers either kind of drag region, because brush-x on a polar chart is honoured
as an angular brush; only brush-angle needs the angular one. A survey of both lab tabs
showed 787 cards with no difference between code and spec; the KPI card lost the region
presets, and the scatter family gained the index declaration its lab cases relied on.
…t types against presets

INTERACTION_PRESET_REQUIREMENTS in core is the single table of what each preset needs;
the registry entries read it. declaredInteractionCapabilities() and
supportedInteractionPresets() turn a template's interactions block into the presets it can
honour by declaration, so hosts and docs can list them without the runtime. The Interactions
lab gains a Coverage tab: all 36 Vega-Lite chart types against all 20 presets, with the
representative test case assembled per row to show which presets are active for that data,
which the chart type supports but the data does not confirm, and which it never offers.
…ver interaction support

validateChart() checks interaction_spec the way the mount does: a malformed spec is an
invalid_interaction_spec error, an entry the assembled chart cannot honour is the same
unsupported_interaction warning the surface reports, and a backend that runs no
interactions reports the spec as ignored. The MCP tool schema gains interaction_spec with
the preset names as an enum, toAssemblyInput passes it through, validate_chart reports the
drops, and list_chart_types returns the interaction presets each chart type supports from
the template declaration.
… chart type supports

A new Using interactions page (docs/interaction-spec.md, with a zh-CN mirror, registered in
the site catalog) explains the spec shape, the twenty presets with what each needs and its
default reset, the reset gestures, how a chart type declares support, the warnings and where
to read them, and the equivalence of a spec entry and a factory call. The API reference gains
interaction_spec on ChartAssemblyInput with a section of its own. The chart-author skill gains
an Interactions section with the authoring rules. The generated Vega-Lite reference prints an
Interactions line per chart type from the same declaration the mount enforces.
…m interaction_spec

The MCP chart view mounts buildInteractiveChart() with the CSP-safe expression
interpreter when the input lists interactions, on the same preview input the static render
sizes; the static render keeps running for the PNG export, and the surface warnings join the
assembler's. The site gains one spec-aware Vega-Lite component, InteractiveVegaLiteView,
used by the editor and by TripleChart whenever the input carries interaction entries; a
TestCase may carry an interactionSpec, and the editor ships an Interactive bar example. The
index chart stage and the chart-to-external lab, which used presets only, now ask for them
in interaction_spec.
@xavier-shaw
xavier (xavier-shaw) marked this pull request as draft September 14, 2026 17:36
Review of Stages A to C with the maintainer:
- the template block is interactionSupport, not interactions
- the drag-region capability is cartesian-region, and the four polar templates declare both
  regions, because a rectangle or lasso resolves their arcs and brush-x is honoured as a sector
- the assembler is the one authority on a chart's capabilities: it derives the confirmed list
  from declaredInteractionCapabilities and the bound encodings, writes _interactionSemantics
  for every Vega-Lite chart, and capabilities is a required field of the admission plan; the
  gates that replayed the old inferred rules are gone, a definition made by hand needs nothing
- preset requirements live in INTERACTION_PRESET_REQUIREMENTS only; the registry entries and
  the definition type no longer carry a copy, and admission no longer imports the registry
- one phrase table for the capabilities, one generator pass shared by the two lab tabs, no
  wrapper around the preview sizing, no dedupe of disjoint warning lists
- the coverage tab pins its header, marks unsupported cells with a cross, and slants the
  preset names
- docs: stages B and C, this review, the future steps set aside, and the changelog
…r the geometry permits

reorder and discreteAxis on every cartesian template except Violin and Range Area, which
refused reorder before, and legend on every template that returns legendFields. The
assembler still confirms each one against the bound encodings, so a chart without a discrete
axis or a discrete legend drops the preset as before; what changes is that a categorical
scatter reorders again and a violin split by shift toggles its legend again.
docs/design-interactions.md, with a zh-CN mirror, explains the interaction model the way
design-semantics.md explains semantic types: the three documents a chart is made of, presets and
definitions, the spec and its resolver, the chart-semantics dictionary, the eight capabilities
with what the type declares and what the data confirms, the requirement table, the match and
the conflict rules, reset, the pipeline, hosts and discovery, and how to extend the model. The
appendix table of all 36 declarations is generated by gen:reference between markers, so it
cannot go stale. The dated decision log docs/design-interaction-spec.md is removed; its history
lives in the commits and the two pull requests. The Vega-Lite reference is regenerated for the
templates that gained declarations.
@xavier-shaw xavier (xavier-shaw) changed the title feat(interactions): admission per chart type, validation and discovery, hosts, and declarative extensions feat(interactions): admission and validation of chart interactions Sep 16, 2026
@xavier-shaw
xavier (xavier-shaw) added this pull request to stack #128 September 16, 2026 00:56
@xavier-shaw
xavier (xavier-shaw) marked this pull request as ready for review September 16, 2026 00:58
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