viz

package
v0.3.44 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 20, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package viz is the visualization core shared by the MCP viz tools (pkg/mcp) and the report renderer (pkg/mcp/reports): the canonical data contracts — flat rows and KPI cards — the chart/column specs, the caps, and the query+jq pipeline that feeds them (query.go). It deliberately knows nothing about MCP itself: tool surfaces, result envelopes and the HTML views stay with their owners. The package lives under pkg/mcp because that is where these contracts were born — they are the viz tools' wire format first, and the report spec reuses them verbatim.

Index

Constants

View Source
const (
	// KPICap bounds a KPI panel: it is a glance surface, not a table. The
	// whole panel always travels inline — no sampling, no refresh channel —
	// and the cap is what keeps that honest.
	KPICap = 32

	// Above the soft limit a browser table stops being usable and the payload
	// stops being reasonable; the hard cap is what a view will never be asked
	// to hold. Between them sits a window the caller opened deliberately with
	// limit/offset, and that is their call to make.
	RowSoftLimit = 2000
	RowHardCap   = 10000
)
View Source
const PagingRecipe = `Three ways, best first: (1) AGGREGATE — a chart wants ` +
	`<object>_bucket_aggregation, not raw rows, and an aggregate is usually what the question ` +
	`actually asked for; (2) NARROW — put a condition in the query's own filter argument, which ` +
	`is also how "only for X" is answered; (3) PAGE — obj(limit: 500, offset: 0) with order_by ` +
	`so the order is stable, then call again with offset: 500 for the next page, each call ` +
	`rendering its own view. Any limit you set is honoured, including a deliberate "first N of ` +
	`the count above" — just tell the user that is what they are looking at.`

PagingRecipe is the one place that spells out how to bound a query, so every refusal points the same way.

Variables

View Source
var (
	ChartTypes    = []string{"line", "bar", "area", "pie", "scatter"}
	KPIDirections = []string{"up_good", "down_good", "neutral"}
	KPIFormats    = []string{"number", "percent"}
)

Functions

func CanonicalRows

func CanonicalRows(v any) ([]map[string]any, error)

CanonicalRows validates the canonical-rows contract: an array of flat objects with scalar values. A single-key object chain (the usual {"module":{"table":[...]}} GraphQL shape) is unwrapped first, so most queries need no jq at all.

func JQPathHint

func JQPathHint(query string) string

JQPathHint recovers the first two selection levels of the query so a failed transform can show the caller the path it probably meant to write.

func QueryHasLimit

func QueryHasLimit(query string) bool

QueryHasLimit reports whether the caller bounded the query themselves, either with a $limit variable or a literal limit: argument. It is a textual check on purpose: the query belongs to the caller and is not re-parsed here.

func QueryLimit

func QueryLimit(query string, vars map[string]any) (int, bool)

QueryLimit recovers the row bound the caller set, from a literal `limit: N` or from the value bound to a $limit variable. Knowing it is what lets the result say "this page is exactly full, there is probably more" instead of leaving the caller to guess from a suspiciously round number.

func QueryRows

func QueryRows(ctx context.Context, q Querier, query string, vars map[string]any, jqTransform string, maxRows int, ttl time.Duration) ([]map[string]any, bool, error)

QueryRows runs a read-only GraphQL query, optionally shapes it with jq, and canonicalizes the outcome into flat rows.

func QueryValue

func QueryValue(ctx context.Context, q Querier, query string, vars map[string]any, jqTransform string, ttl time.Duration) (any, error)

QueryValue is the shared query pipeline: read-only hint, cache hint, jq fail-fast compile, execute, transform, and a JSON round-trip that normalizes engine/gojq value types into plain maps. What the value MEANS — rows or KPI cards — is the caller's canonicalizer's business.

Types

type ChartSpec

type ChartSpec struct {
	Type    string   `json:"type" jsonschema_description:"line | bar | area | pie | scatter"`
	X       string   `json:"x,omitempty" jsonschema_description:"Row field for the category/x value"`
	Y       []string `json:"y,omitempty" jsonschema_description:"Row fields holding values; several = one series each (wide form)"`
	Series  string   `` /* 130-byte string literal not displayed */
	Stacked bool     `json:"stacked,omitempty" jsonschema_description:"Stack the series"`
}

type ColumnSpec

type ColumnSpec struct {
	Field  string `json:"field" jsonschema_description:"Row field"`
	Label  string `json:"label,omitempty" jsonschema_description:"Header label (default: field name)"`
	Format string `json:"format,omitempty" jsonschema_description:"number to right-align and group digits"`
	Align  string `json:"align,omitempty" jsonschema_description:"left | right"`
}

type KPI

type KPI struct {
	Label     string    `json:"label" jsonschema_description:"Card caption"`
	Value     any       `json:"value" jsonschema_description:"The headline value: a number, or a short string"`
	Unit      string    `json:"unit,omitempty" jsonschema_description:"Rendered next to the value ($, %, ms, …)"`
	Format    string    `json:"format,omitempty" jsonschema_description:"number | percent"`
	Delta     *float64  `json:"delta,omitempty" jsonschema_description:"Absolute change vs the comparison period"`
	DeltaPct  *float64  `json:"delta_pct,omitempty" jsonschema_description:"Change in percent vs the comparison period"`
	Direction string    `json:"direction,omitempty" jsonschema_description:"up_good | down_good | neutral — colours the delta"`
	Trend     []float64 `json:"trend,omitempty" jsonschema_description:"Values drawn as a sparkline under the number"`
	Subtitle  string    `json:"subtitle,omitempty" jsonschema_description:"Small line under the value (e.g. \"vs July\")"`
}

KPI is one card on a KPI panel. Label and value are the card; everything else decorates it.

func CanonicalKPIs

func CanonicalKPIs(v any) ([]KPI, error)

CanonicalKPIs validates the canonical KPI-card contract: an array of card objects, label+value required, trend the only array field. Unknown keys are rejected by name — a typo like delta_percent must fail loudly with the allowed list, not render a bare card.

type Querier

type Querier interface {
	Query(ctx context.Context, query string, vars map[string]any) (*types.Response, error)
}

Querier is the one engine capability the pipeline needs; types.Querier satisfies it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL