Dataface Tasks

Add JSON render output format

IDMCP_ANALYST_AGENT-ADD_JSON_RENDER_OUTPUT_FORMAT
Statuscompleted
Priorityp1
Milestonem1-ft-analytics-analyst-pilot
Ownerdata-ai-engineer-architect
Completed bydave
Completed2026-03-17

Problem

The render pipeline outputs visual formats (SVG, HTML, PNG, PDF, terminal) but has no structured-data output. AI agents calling via MCP get expensive HTML blobs they can't reason over. Tests that want to assert on resolved chart decisions (auto type, auto fields) must parse SVG. There's no way to get "what did the engine decide?" as data.

Context

  • dataface/core/render/renderer.py — top-level render() with format dispatch (svg/html/png/pdf/terminal)
  • dataface/core/render/chart/rendering.py_render_chart_item_inner() does: execute query → resolve chart → render SVG. The resolution step (resolve_chart()) is where auto chart type, auto fields, enrichment all happen.
  • dataface/core/render/chart/pipeline.pyresolve_chart() returns ResolvedChart dataclass
  • dataface/core/render/chart/models.pyResolvedChart (dataclass), ChartIntent, EnrichmentPatch
  • dataface/core/compile/compiled_types.pyCompiledFace (Pydantic), CompiledChart, LayoutItem
  • dataface/core/render/faces.pyrender_face_svg() walks the layout tree
  • Chart-level JSON already exists (render_chart(format="json")) but produces Vega-Lite specs, not resolved semantics
  • Related: issue-369 (text/describe format for AI agents) — this is the foundation step

Possible Solutions

  1. Recommended — Light wrapper: walk layout, serialize resolved objects + data. Add format="json" to render(). Walk the layout tree like render_face_svg does, but instead of building SVG, execute queries, resolve charts via resolve_chart(), and collect into dicts. Use dataclasses.asdict() for ResolvedChart, model_dump() for CompiledFace/LayoutItem. Attach executed query data. Return json.dumps(). No new schema file — the output shape is defined by the existing models. Evolves naturally as models evolve.

  2. Define a separate JSON schema / Pydantic model for the output. More explicit contract, but adds a parallel type hierarchy that must be kept in sync with the compile/render models. Premature at this stage.

Plan

Files to modify: - dataface/core/render/renderer.py — add elif format == "json" branch calling _to_json() - dataface/core/render/json_format.py (new) — render_face_json() that walks layout tree, executes queries, resolves charts, serializes

Tests: - tests/core/test_json_format.py (new) — test JSON output contains resolved chart type, executed data, layout structure

Steps: 1. Write failing test: render a simple face with an auto-type chart, assert JSON output contains resolved chart_type and data 2. Implement render_face_json() — walk layout items, for each chart: execute query, resolve, serialize. For nested faces: recurse. 3. Wire into render() as format="json" 4. Run just ci

Implementation Progress

2026-03-17: Implementation complete

Files created: - dataface/core/render/json_format.pyrender_face_json() walks layout tree, executes queries via executor.execute_chart(), resolves charts via resolve_chart(), serializes with dataclasses.asdict() (skipping source_chart), returns JSON string. - tests/core/test_json_format.py — 7 tests covering: basic output, resolved fields, executed data, auto type resolution, nested faces, multiple charts, KPI charts.

Files modified: - dataface/core/render/renderer.py — Added early return for format="json" before SVG rendering (no SVG overhead). - dataface/cli/commands/render.py — JSON output prints to stdout (like terminal format). - dataface/cli/main.py — Updated --format help text to include "json".

Key decisions: - JSON format short-circuits before SVG rendering in render() — no unnecessary SVG overhead. - Uses dataclasses.asdict() for ResolvedChart with source_chart popped (avoids circular serialization of the full CompiledChart). - Uses model_dump() for Pydantic Variable objects. - Custom _json_default handles DotDict (→ dict) and set (→ sorted list). - Output shape: {id, title, variables?, items: [{type: "chart", chart: {...}, data: [...]}, {type: "face", face: {id, title, items: [...]}}]}

QA Exploration

  • [x] QA exploration completed (or N/A for non-UI tasks)

Review Feedback

  • [ ] Review cleared