semiotic 3.5.4 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/CLAUDE.md +196 -175
  2. package/README.md +52 -15
  3. package/ai/cli.js +41 -0
  4. package/ai/componentMetadata.cjs +11 -2
  5. package/ai/dist/mcp-server.js +454 -4
  6. package/ai/examples.md +98 -0
  7. package/ai/schema.json +614 -9
  8. package/ai/system-prompt.md +5 -2
  9. package/dist/components/AccessibleNavTree.d.ts +25 -0
  10. package/dist/components/Annotation.d.ts +40 -14
  11. package/dist/components/ChartContainer.d.ts +32 -2
  12. package/dist/components/ai/annotationProvenance.d.ts +349 -0
  13. package/dist/components/ai/audienceProfile.d.ts +147 -0
  14. package/dist/components/ai/audiences.d.ts +31 -0
  15. package/dist/components/ai/chartCapabilities.d.ts +55 -0
  16. package/dist/components/ai/chartCapabilityTypes.d.ts +254 -0
  17. package/dist/components/ai/chartRoles.d.ts +27 -0
  18. package/dist/components/ai/conversationArc.d.ts +379 -0
  19. package/dist/components/ai/dataScaleProfile.d.ts +320 -0
  20. package/dist/components/ai/describeChart.d.ts +114 -0
  21. package/dist/components/ai/diffProfile.d.ts +51 -0
  22. package/dist/components/ai/inferIntent.d.ts +24 -0
  23. package/dist/components/ai/intents.d.ts +34 -0
  24. package/dist/components/ai/navigationTree.d.ts +45 -0
  25. package/dist/components/ai/profileData.d.ts +16 -0
  26. package/dist/components/ai/qualityFixtures.d.ts +2 -0
  27. package/dist/components/ai/qualityScorecard.d.ts +82 -0
  28. package/dist/components/ai/readerGrounding.d.ts +70 -0
  29. package/dist/components/ai/repairChartConfig.d.ts +73 -0
  30. package/dist/components/ai/streamingTypes.d.ts +64 -0
  31. package/dist/components/ai/suggestCharts.d.ts +109 -0
  32. package/dist/components/ai/suggestDashboard.d.ts +92 -0
  33. package/dist/components/ai/suggestStreamCharts.d.ts +34 -0
  34. package/dist/components/ai/suggestStretchCharts.d.ts +60 -0
  35. package/dist/components/ai/useChartSuggestions.d.ts +22 -0
  36. package/dist/components/ai/useConversationArc.d.ts +89 -0
  37. package/dist/components/ai/useNavigationSync.d.ts +61 -0
  38. package/dist/components/ai/variantDiscovery.d.ts +168 -0
  39. package/dist/components/charts/geo/ChoroplethMap.capability.d.ts +2 -0
  40. package/dist/components/charts/geo/DistanceCartogram.capability.d.ts +2 -0
  41. package/dist/components/charts/geo/FlowMap.capability.d.ts +2 -0
  42. package/dist/components/charts/geo/ProportionalSymbolMap.capability.d.ts +2 -0
  43. package/dist/components/charts/index.d.ts +1 -1
  44. package/dist/components/charts/network/ChordDiagram.capability.d.ts +2 -0
  45. package/dist/components/charts/network/CirclePack.capability.d.ts +2 -0
  46. package/dist/components/charts/network/ForceDirectedGraph.capability.d.ts +2 -0
  47. package/dist/components/charts/network/OrbitDiagram.capability.d.ts +2 -0
  48. package/dist/components/charts/network/ProcessSankey.capability.d.ts +2 -0
  49. package/dist/components/charts/network/SankeyDiagram.capability.d.ts +2 -0
  50. package/dist/components/charts/network/TreeDiagram.capability.d.ts +2 -0
  51. package/dist/components/charts/network/Treemap.capability.d.ts +2 -0
  52. package/dist/components/charts/ordinal/BarChart.capability.d.ts +2 -0
  53. package/dist/components/charts/ordinal/BoxPlot.capability.d.ts +2 -0
  54. package/dist/components/charts/ordinal/DonutChart.capability.d.ts +2 -0
  55. package/dist/components/charts/ordinal/DotPlot.capability.d.ts +2 -0
  56. package/dist/components/charts/ordinal/FunnelChart.capability.d.ts +2 -0
  57. package/dist/components/charts/ordinal/GaugeChart.capability.d.ts +2 -0
  58. package/dist/components/charts/ordinal/GroupedBarChart.capability.d.ts +2 -0
  59. package/dist/components/charts/ordinal/Histogram.capability.d.ts +2 -0
  60. package/dist/components/charts/ordinal/Histogram.d.ts +4 -2
  61. package/dist/components/charts/ordinal/LikertChart.capability.d.ts +2 -0
  62. package/dist/components/charts/ordinal/LikertChart.d.ts +1 -1
  63. package/dist/components/charts/ordinal/LikertChart.defaults.d.ts +1 -0
  64. package/dist/components/charts/ordinal/PieChart.capability.d.ts +2 -0
  65. package/dist/components/charts/ordinal/RidgelinePlot.capability.d.ts +2 -0
  66. package/dist/components/charts/ordinal/StackedBarChart.capability.d.ts +2 -0
  67. package/dist/components/charts/ordinal/SwarmPlot.capability.d.ts +2 -0
  68. package/dist/components/charts/ordinal/SwimlaneChart.capability.d.ts +2 -0
  69. package/dist/components/charts/ordinal/ViolinPlot.capability.d.ts +2 -0
  70. package/dist/components/charts/realtime/RealtimeHeatmap.capability.d.ts +2 -0
  71. package/dist/components/charts/realtime/RealtimeHeatmap.d.ts +3 -0
  72. package/dist/components/charts/realtime/RealtimeHistogram.capability.d.ts +2 -0
  73. package/dist/components/charts/realtime/RealtimeHistogram.d.ts +3 -0
  74. package/dist/components/charts/realtime/RealtimeLineChart.capability.d.ts +2 -0
  75. package/dist/components/charts/realtime/RealtimeLineChart.d.ts +3 -0
  76. package/dist/components/charts/realtime/RealtimeSwarmChart.capability.d.ts +2 -0
  77. package/dist/components/charts/realtime/RealtimeSwarmChart.d.ts +3 -0
  78. package/dist/components/charts/realtime/RealtimeWaterfallChart.capability.d.ts +2 -0
  79. package/dist/components/charts/realtime/RealtimeWaterfallChart.d.ts +3 -0
  80. package/dist/components/charts/realtime/TemporalHistogram.capability.d.ts +7 -0
  81. package/dist/components/charts/shared/annotationHierarchy.d.ts +42 -0
  82. package/dist/components/charts/shared/annotationResolvers.d.ts +3 -2
  83. package/dist/components/charts/shared/annotationRules.d.ts +16 -0
  84. package/dist/components/charts/shared/annotationTypes.d.ts +14 -0
  85. package/dist/components/charts/shared/auditAccessibility.d.ts +90 -0
  86. package/dist/components/charts/shared/chartSpecs.d.ts +2 -37
  87. package/dist/components/charts/shared/diagnoseConfig.d.ts +4 -6
  88. package/dist/components/charts/shared/selectionUtils.d.ts +5 -2
  89. package/dist/components/charts/shared/streamPropsHelpers.d.ts +2 -0
  90. package/dist/components/charts/shared/types.d.ts +5 -1
  91. package/dist/components/charts/value/BigNumber.capability.d.ts +13 -0
  92. package/dist/components/charts/value/BigNumber.d.ts +14 -0
  93. package/dist/components/charts/value/formatting.d.ts +40 -0
  94. package/dist/components/charts/value/thresholdSparkline.d.ts +40 -0
  95. package/dist/components/charts/value/types.d.ts +292 -0
  96. package/dist/components/charts/xy/AreaChart.capability.d.ts +10 -0
  97. package/dist/components/charts/xy/BubbleChart.capability.d.ts +2 -0
  98. package/dist/components/charts/xy/CandlestickChart.capability.d.ts +2 -0
  99. package/dist/components/charts/xy/ConnectedScatterplot.capability.d.ts +2 -0
  100. package/dist/components/charts/xy/DifferenceChart.capability.d.ts +8 -0
  101. package/dist/components/charts/xy/Heatmap.capability.d.ts +9 -0
  102. package/dist/components/charts/xy/LineChart.capability.d.ts +9 -0
  103. package/dist/components/charts/xy/MinimapChart.capability.d.ts +2 -0
  104. package/dist/components/charts/xy/MultiAxisLineChart.capability.d.ts +2 -0
  105. package/dist/components/charts/xy/QuadrantChart.capability.d.ts +2 -0
  106. package/dist/components/charts/xy/QuadrantChart.d.ts +5 -2
  107. package/dist/components/charts/xy/QuadrantChart.defaults.d.ts +2 -0
  108. package/dist/components/charts/xy/Scatterplot.capability.d.ts +2 -0
  109. package/dist/components/charts/xy/StackedAreaChart.capability.d.ts +2 -0
  110. package/dist/components/data/DataSummarizer.d.ts +45 -0
  111. package/dist/components/realtime/lifecycleBands.d.ts +44 -0
  112. package/dist/components/realtime/types.d.ts +23 -8
  113. package/dist/components/recipes/annotationDensity.d.ts +69 -0
  114. package/dist/components/recipes/annotationLayout.d.ts +93 -0
  115. package/dist/components/semiotic-ai.d.ts +58 -0
  116. package/dist/components/semiotic-realtime.d.ts +2 -0
  117. package/dist/components/semiotic-recipes.d.ts +4 -0
  118. package/dist/components/semiotic-utils.d.ts +8 -0
  119. package/dist/components/semiotic-value.d.ts +55 -0
  120. package/dist/components/semiotic-xy.d.ts +1 -1
  121. package/dist/components/semiotic.d.ts +8 -1
  122. package/dist/components/server/staticAnnotations.d.ts +2 -0
  123. package/dist/components/store/useChartFocus.d.ts +43 -0
  124. package/dist/components/store/useChartInterrogation.d.ts +141 -0
  125. package/dist/components/stream/AccessibleDataTable.d.ts +10 -1
  126. package/dist/components/stream/NetworkSVGOverlay.d.ts +11 -5
  127. package/dist/components/stream/OrdinalSVGOverlay.d.ts +2 -0
  128. package/dist/components/stream/SVGOverlay.d.ts +2 -0
  129. package/dist/components/stream/geoTypes.d.ts +3 -0
  130. package/dist/components/stream/networkTypes.d.ts +2 -0
  131. package/dist/components/stream/ordinalTypes.d.ts +2 -0
  132. package/dist/components/stream/types.d.ts +2 -0
  133. package/dist/geo.min.js +1 -1
  134. package/dist/geo.module.min.js +1 -1
  135. package/dist/network.min.js +1 -1
  136. package/dist/network.module.min.js +1 -1
  137. package/dist/ordinal.min.js +1 -1
  138. package/dist/ordinal.module.min.js +1 -1
  139. package/dist/realtime.min.js +1 -1
  140. package/dist/realtime.module.min.js +1 -1
  141. package/dist/semiotic-ai.d.ts +58 -0
  142. package/dist/semiotic-ai.min.js +1 -1
  143. package/dist/semiotic-ai.module.min.js +1 -1
  144. package/dist/semiotic-realtime.d.ts +2 -0
  145. package/dist/semiotic-recipes.d.ts +4 -0
  146. package/dist/semiotic-recipes.min.js +1 -1
  147. package/dist/semiotic-recipes.module.min.js +1 -1
  148. package/dist/semiotic-themes.min.js +1 -1
  149. package/dist/semiotic-themes.module.min.js +1 -1
  150. package/dist/semiotic-utils.d.ts +8 -0
  151. package/dist/semiotic-utils.min.js +1 -1
  152. package/dist/semiotic-utils.module.min.js +1 -1
  153. package/dist/semiotic-value.d.ts +55 -0
  154. package/dist/semiotic-value.min.js +2 -0
  155. package/dist/semiotic-value.module.min.js +2 -0
  156. package/dist/semiotic-xy.d.ts +1 -1
  157. package/dist/semiotic.d.ts +8 -1
  158. package/dist/semiotic.min.js +1 -1
  159. package/dist/semiotic.module.min.js +1 -1
  160. package/dist/server.min.js +1 -1
  161. package/dist/server.module.min.js +1 -1
  162. package/dist/xy.min.js +1 -1
  163. package/dist/xy.module.min.js +1 -1
  164. package/package.json +28 -5
@@ -0,0 +1,320 @@
1
+ /**
2
+ * Scale-aware suggestion overlay. The companion to AudienceProfile: where
3
+ * AudienceProfile describes *who* reads the chart, DataScaleProfile and
4
+ * DataQualityProfile describe *how big* and *how clean* the data actually is.
5
+ *
6
+ * Semiotic does not measure scale or quality from the data passed to it —
7
+ * the row data may be a sample, a future projection, or completely absent.
8
+ * Orgs declare these facts up front and the suggestion engine biases
9
+ * rankings accordingly. Identical philosophy to AudienceProfile.
10
+ *
11
+ * The two profiles compose additively with the audience overlay:
12
+ *
13
+ * composite = baseScore
14
+ * + scaleBias(scale, capability, profile)
15
+ * + qualityBias(quality, capability, profile)
16
+ * + audienceBias(audience, capability)
17
+ *
18
+ * Each layer can be omitted independently. Most adjust ranking only, but
19
+ * per-chart scale preferences can also hard-filter via `minBand`/`maxBand`
20
+ * exclusions in addition to `fits()`.
21
+ */
22
+ import type { ChartCapability, ChartDataProfile } from "./chartCapabilityTypes";
23
+ /**
24
+ * Coarse row-count band. Used for grouping suggestions ("show me charts that
25
+ * work at small scale") and for surfacing scale-band on each suggestion.
26
+ *
27
+ * Defaults below are research-backed starting points — see DEFAULT_SCALE_THRESHOLDS.
28
+ */
29
+ export type ScaleBand = "tiny" | "small" | "medium" | "large" | "huge";
30
+ /**
31
+ * Coarse cardinality band. A "low"-cardinality field is bar-chart-able;
32
+ * "high" almost always wants treemap, force layout, or aggregation.
33
+ */
34
+ export type CardinalityBand = "low" | "medium" | "high";
35
+ /**
36
+ * Field-count band. "narrow" datasets need at most one mark per column;
37
+ * "wide" datasets typically need a matrix-style layout (parallel coords,
38
+ * scatterplot matrix, heatmap of fields).
39
+ */
40
+ export type FieldBand = "narrow" | "typical" | "wide";
41
+ /**
42
+ * Research-backed default breakpoints. Treat as starting points — orgs override
43
+ * via `DataScaleProfile.thresholds`.
44
+ *
45
+ * Row thresholds:
46
+ * • tiny ≤ 3 — single-value territory; recommendation often "a value, not a chart"
47
+ * • small ≤ 25 — Miller's 7±2 plus a comfortable buffer; bar/pie/dot legible
48
+ * • medium ≤ 250 — line/scatter/area sweet spot (Cleveland-McGill, position channel)
49
+ * • large ≤ 5000 — dense scatter/heatmap/ridgeline (Munzner ch. 10 quantitative encoding)
50
+ * • huge > 5000 — aggregation, sampling, density reduction required (Few, "Now You See It")
51
+ *
52
+ * Cardinality (per categorical field):
53
+ * • low ≤ 7 — Miller (1956); robust bar chart
54
+ * • medium ≤ 25 — bar still legible with care; treemap competitive
55
+ * • high > 25 — treemap, packed force, or aggregation
56
+ *
57
+ * Field count:
58
+ * • narrow ≤ 3 — single-mark-per-row layouts dominate
59
+ * • typical ≤ 10 — standard catalog applies
60
+ * • wide > 10 — parallel coords / scatterplot matrix territory
61
+ *
62
+ * References:
63
+ * - Miller, G.A. (1956). "The Magical Number Seven, Plus or Minus Two."
64
+ * Psychological Review, 63(2), 81–97.
65
+ * - Cleveland, W.S. & McGill, R. (1984). "Graphical Perception: Theory,
66
+ * Experimentation, and Application to the Development of Graphical Methods."
67
+ * JASA, 79(387), 531–554.
68
+ * - Munzner, T. (2014). Visualization Analysis and Design, ch. 10.
69
+ * - Few, S. (2009). Now You See It: Simple Visualization Techniques for
70
+ * Quantitative Analysis.
71
+ */
72
+ export declare const DEFAULT_SCALE_THRESHOLDS: {
73
+ readonly rows: {
74
+ readonly tiny: 3;
75
+ readonly small: 25;
76
+ readonly medium: 250;
77
+ readonly large: 5000;
78
+ };
79
+ readonly cardinality: {
80
+ readonly low: 7;
81
+ readonly medium: 25;
82
+ };
83
+ readonly fields: {
84
+ readonly narrow: 3;
85
+ readonly typical: 10;
86
+ };
87
+ };
88
+ export interface ScaleThresholds {
89
+ rows?: {
90
+ tiny?: number;
91
+ small?: number;
92
+ medium?: number;
93
+ large?: number;
94
+ };
95
+ cardinality?: {
96
+ low?: number;
97
+ medium?: number;
98
+ };
99
+ fields?: {
100
+ narrow?: number;
101
+ typical?: number;
102
+ };
103
+ }
104
+ /**
105
+ * Per-chart scale preference — analogous to AudienceProfile.targets but scoped
106
+ * to scale fit. Lets orgs say "we'd rather not see Heatmap below 100 rows even
107
+ * when the engine thinks it's competitive."
108
+ */
109
+ export interface ChartScalePreference {
110
+ /** Add this many points to the composite score for this chart. Range -3..+3. */
111
+ bias?: number;
112
+ /** Restrict suggestion of this chart to data with rows in this band or above. */
113
+ minBand?: ScaleBand;
114
+ /** Restrict suggestion of this chart to data with rows in this band or below. */
115
+ maxBand?: ScaleBand;
116
+ /** Human-readable rationale. Surfaces in suggestion.reasons when the rule fires. */
117
+ reason?: string;
118
+ }
119
+ /**
120
+ * Forward-looking declaration of how big the user's data actually is. The row
121
+ * data passed to suggestCharts may be a sample, a stub, or a future projection;
122
+ * DataScaleProfile is what the chart needs to actually handle at production.
123
+ *
124
+ * Every field is optional. Omitting a field falls back to what profileData()
125
+ * measured from the sample. Specifying a field overrides the measurement.
126
+ */
127
+ export interface DataScaleProfile {
128
+ /**
129
+ * Production row count. May be larger than the sample passed to suggestCharts.
130
+ * Accepts a band string ("medium") for hand-waving estimates, or an exact number.
131
+ */
132
+ rows?: number | ScaleBand;
133
+ /**
134
+ * Production field/column count. Affects parallel-coords / matrix recommendations.
135
+ */
136
+ fields?: number | FieldBand;
137
+ /**
138
+ * Per-field cardinality. Use field name as key; value is distinct count or band.
139
+ * @example cardinality: { region: 12, status: "low" }
140
+ */
141
+ cardinality?: Partial<Record<string, number | CardinalityBand>>;
142
+ /**
143
+ * Aggregate cardinality fallback when per-field isn't declared. The "typical"
144
+ * categorical field in this dataset has this much cardinality.
145
+ */
146
+ typicalCardinality?: number | CardinalityBand;
147
+ /**
148
+ * How does this dataset grow?
149
+ * • "static" — fixed, or refreshed periodically as a whole
150
+ * • "appending" — grows by adding rows; old rows are stable
151
+ * • "windowed" — sliding window of recent data (e.g. last 7 days)
152
+ * Affects streaming recommendations and decay/staleness defaults.
153
+ */
154
+ growth?: "static" | "appending" | "windowed";
155
+ /**
156
+ * Override the default scale thresholds for this profile. Orgs use this to
157
+ * encode their own definition of "small" / "medium" / "large" — e.g. a BI
158
+ * shop where 10k rows is "small" because dashboards typically run 100k+.
159
+ */
160
+ thresholds?: ScaleThresholds;
161
+ /**
162
+ * Per-chart preferences. Like AudienceProfile.familiarity / .targets,
163
+ * orgs can override scale fit on a per-component basis.
164
+ * @example charts: { Heatmap: { minBand: "medium", reason: "below 50 rows the cells are dominant noise" } }
165
+ */
166
+ charts?: Partial<Record<string, ChartScalePreference>>;
167
+ /** Display name. Surfaced in suggestion.reasons when scale bias fires. */
168
+ name?: string;
169
+ }
170
+ /**
171
+ * User-declared data-quality profile. Quality issues affect *which treatment*
172
+ * of a chart is recommended (broken vs connected lines, log vs linear, with vs
173
+ * without regression overlay), and can add caveats. Quality biases score
174
+ * modestly but biases caveats heavily.
175
+ */
176
+ export interface DataQualityProfile {
177
+ /**
178
+ * Fraction of non-null values (0..1). Map of field name → completeness, or
179
+ * a single aggregate. 1.0 = complete; 0.5 = half the values missing.
180
+ * @example completeness: { revenue: 0.98, cohort: 0.62 }
181
+ */
182
+ completeness?: Partial<Record<string, number>> | number;
183
+ /**
184
+ * Fraction of values flagged as outliers (0..1). Affects recommendations
185
+ * for regression overlays, log scales, and outlier-detection intent.
186
+ * @example outliers: { revenue: 0.04 }
187
+ */
188
+ outliers?: Partial<Record<string, number>> | number;
189
+ /**
190
+ * Fraction of values that don't match the dominant type for the field (0..1).
191
+ * Strings mixed into a numeric column, dates in arbitrary formats, etc.
192
+ * High heterogeneity → caveats and possibly reject from numeric-required charts.
193
+ */
194
+ typeHeterogeneity?: Partial<Record<string, number>> | number;
195
+ /** Display name. Surfaced in suggestion.reasons when quality bias fires. */
196
+ name?: string;
197
+ }
198
+ /**
199
+ * Classify a row count into a ScaleBand using the profile's thresholds (or defaults).
200
+ */
201
+ export declare function classifyRowBand(rows: number, scale?: DataScaleProfile): ScaleBand;
202
+ /**
203
+ * Classify cardinality. Per-field if the field is named; otherwise the aggregate.
204
+ */
205
+ export declare function classifyCardinalityBand(count: number, scale?: DataScaleProfile): CardinalityBand;
206
+ /**
207
+ * Classify field count.
208
+ */
209
+ export declare function classifyFieldBand(count: number, scale?: DataScaleProfile): FieldBand;
210
+ /**
211
+ * Compare two bands by order (tiny < small < medium < large < huge).
212
+ * Returns negative if a < b, zero if equal, positive if a > b.
213
+ */
214
+ export declare function compareBands(a: ScaleBand, b: ScaleBand): number;
215
+ /**
216
+ * Resolve a declared `rows` value (number, band, or undefined) to an effective
217
+ * row count for bias calculations. Bands resolve to the midpoint of their range.
218
+ *
219
+ * When the user declares a number, we use it directly. When they declare a band,
220
+ * we use a representative point inside that band. When they declare nothing,
221
+ * we fall back to the profile's measured rowCount.
222
+ */
223
+ export declare function resolveRowsToNumber(declared: number | ScaleBand | undefined, measuredRows: number, scale?: DataScaleProfile): number;
224
+ /**
225
+ * Resolve a declared cardinality value to a number.
226
+ */
227
+ export declare function resolveCardinalityToNumber(declared: number | CardinalityBand | undefined, measured: number | undefined, scale?: DataScaleProfile): number | undefined;
228
+ /**
229
+ * The effective scale view the engine reasons over. Merges the declared
230
+ * DataScaleProfile with the profile's measured stats. Surfaced on each
231
+ * Suggestion so callers can detect threshold crossings ("you outgrew this
232
+ * chart") and so the conversational layer can narrate scale rationale.
233
+ */
234
+ export interface EffectiveScale {
235
+ /** Effective row count after merging declared scale with measured profile. */
236
+ rows: number;
237
+ /** Band classification of the effective row count. */
238
+ rowBand: ScaleBand;
239
+ /** Effective field count. */
240
+ fields: number;
241
+ /** Band classification of the effective field count. */
242
+ fieldBand: FieldBand;
243
+ /** Typical-category cardinality, if known. */
244
+ typicalCardinality?: number;
245
+ /** Band of that cardinality. */
246
+ cardinalityBand?: CardinalityBand;
247
+ /** Pass-through of growth mode (defaults to "static"). */
248
+ growth: "static" | "appending" | "windowed";
249
+ /** Source of the rows number: "declared" if user provided, "measured" otherwise. */
250
+ rowsSource: "declared" | "measured";
251
+ }
252
+ /**
253
+ * Compute the effective scale for a profile under the optional declared scale.
254
+ * When no scale is declared, the profile's measured stats define everything.
255
+ */
256
+ export declare function computeEffectiveScale(profile: ChartDataProfile, scale?: DataScaleProfile): EffectiveScale;
257
+ export interface ScaleBiasResult {
258
+ /** Score delta to apply to the suggestion composite. */
259
+ delta: number;
260
+ /** Reasons to append to the suggestion.reasons[] array. */
261
+ reasons: string[];
262
+ /** Caveats to append (mostly from quality). */
263
+ caveats: string[];
264
+ /** True if a per-chart minBand/maxBand restriction excluded this chart. */
265
+ excluded: boolean;
266
+ }
267
+ /**
268
+ * Apply scale and quality bias to a chart's composite score.
269
+ *
270
+ * Two terms compose additively beyond the audience bias:
271
+ * • Capability scale-fit: each capability optionally declares a `scaleFit`
272
+ * function returning {delta, reason?, caveat?}. Range ±SCALE_BIAS_MAX.
273
+ * • Org per-chart preference: `DataScaleProfile.charts[component]` can
274
+ * pin a chart to a band range (excludes outside it) and add an
275
+ * org-defined bias. Range ±PREFERENCE_BIAS_MAX.
276
+ *
277
+ * Pure function — used by both `suggestCharts` and any caller that needs
278
+ * to reason about a single (capability × variant × scale) tuple.
279
+ */
280
+ export declare function applyScaleBias(capability: ChartCapability, profile: ChartDataProfile, effectiveScale: EffectiveScale, scale: DataScaleProfile | undefined, quality: DataQualityProfile | undefined): ScaleBiasResult;
281
+ /**
282
+ * Declarative sugar for capability authors. Convert a hint object into a
283
+ * scaleFit function. The hint object expresses the sweet-spot row range and
284
+ * optional cardinality range; the engine derives a smooth bias curve.
285
+ *
286
+ * Use this when the chart's scale behavior is straightforward. For more
287
+ * sophisticated logic (e.g. "smoothing variant degrades faster at high cardinality"),
288
+ * write a scaleFit function directly.
289
+ *
290
+ * @example
291
+ * scaleFit: scaleHints({
292
+ * rows: { sweetSpot: [25, 1000], caveatAbove: 5000 },
293
+ * cardinality: { sweetSpot: [3, 15], caveatAbove: 30 },
294
+ * })
295
+ */
296
+ export interface ScaleHintInput {
297
+ rows?: {
298
+ sweetSpot: [number, number];
299
+ caveatAbove?: number;
300
+ caveatBelow?: number;
301
+ };
302
+ cardinality?: {
303
+ sweetSpot: [number, number];
304
+ caveatAbove?: number;
305
+ };
306
+ }
307
+ export type ScaleFitFn = (profile: ChartDataProfile, effective: EffectiveScale, scale: DataScaleProfile | undefined) => ScaleFitResult | null;
308
+ export interface ScaleFitResult {
309
+ delta: number;
310
+ reason?: string;
311
+ caveats?: string[];
312
+ }
313
+ export type QualityFitFn = (profile: ChartDataProfile, quality: DataQualityProfile) => ScaleFitResult | null;
314
+ /**
315
+ * Build a scaleFit function from a declarative hint shape. Smooth bias —
316
+ * positive inside the sweet spot, decays toward zero, and tips negative
317
+ * past the caveat thresholds. The decay is gradual rather than a cliff
318
+ * so a chart isn't all-or-nothing at the boundary.
319
+ */
320
+ export declare function scaleHints(hint: ScaleHintInput): ScaleFitFn;
@@ -0,0 +1,114 @@
1
+ import type { Datum } from "../charts/shared/datumTypes";
2
+ import type { ChartCapability, ChartFamily } from "./chartCapabilityTypes";
3
+ import type { IntentId } from "./intents";
4
+ import type { AudienceProfile } from "./audienceProfile";
5
+ /**
6
+ * describeChart — generate a layered natural-language description of a chart
7
+ * from its `(component, props)` config, following Lundgard & Satyanarayan's
8
+ * four-level model of semantic content (IEEE VIS 2021):
9
+ *
10
+ * L1 (encoding) — chart type and what's mapped to which channel.
11
+ * L2 (statistics) — ranges, mean, extrema (the level blind/low-vision
12
+ * readers rank *most* useful, alongside L3).
13
+ * L3 (trends) — overall direction and notable shape over an ordered axis.
14
+ * L4 (intent) — the *illocutionary* sentence: what communicative act the
15
+ * chart performs and which feature it asks the reader to act
16
+ * on ("This is an alerting chart; the May spike warrants a
17
+ * closer look."). Opt-in — only emitted when the caller
18
+ * supplies the chart's capability descriptor (or an explicit
19
+ * communicative act). Without that intent metadata, the
20
+ * domain meaning stays the author's `summary` or an LLM's
21
+ * job, as before.
22
+ *
23
+ * Pure, SSR-safe, dependency-light (the new capability/audience inputs are
24
+ * type-only — no runtime registry pull). Wired into ChartContainer as an opt-in
25
+ * full-accessibility affordance (see ChartContainer's `describe` prop); also
26
+ * usable directly, surfaced by the accessibility audit, and composed by
27
+ * `buildReaderGrounding` into the agent-reader payload.
28
+ */
29
+ export type DescribeLevel = "l1" | "l2" | "l3" | "l4";
30
+ /**
31
+ * The communicative act a chart performs — its illocutionary force, the verb
32
+ * behind "what is this chart *doing*?". Derived from the dominant intent (or
33
+ * the chart family as a fallback) and used to phrase the L4 sentence.
34
+ */
35
+ export type CommunicativeAct = "alerting" | "tracking" | "comparing" | "ranking" | "apportioning" | "characterizing" | "relating" | "tracing" | "nesting" | "locating" | "presenting";
36
+ /**
37
+ * Lightweight intent context for the L4 sentence. Either hand `describeChart`
38
+ * a full {@link ChartCapability} (its static `intentScores` are read; function
39
+ * scorers are skipped since no data profile is in scope here) or this resolved
40
+ * shape — e.g. a `Suggestion`'s already-resolved `{ family, intentScores }`,
41
+ * which is the most precise source.
42
+ */
43
+ export interface DescribeCapabilityContext {
44
+ /** Chart family — anchors the communicative act when intent scores are absent. */
45
+ family?: ChartFamily;
46
+ /** Per-intent scores (0..5), already resolved. The top-scoring intent picks the act. */
47
+ intentScores?: Partial<Record<IntentId, number>>;
48
+ /** Explicit override — skips intent/family inference entirely. */
49
+ act?: CommunicativeAct;
50
+ }
51
+ export interface DescribeChartResult {
52
+ /** The selected levels joined into one description (what you'd feed a summary). */
53
+ text: string;
54
+ /** Each level on its own, so callers can pick verbosity. */
55
+ levels: {
56
+ l1?: string;
57
+ l2?: string;
58
+ l3?: string;
59
+ l4?: string;
60
+ };
61
+ /**
62
+ * The author's marked features, as a sentence — present only when the chart
63
+ * carries `annotations`. An annotation is author intent in its purest form,
64
+ * so it leads `text` ahead of the auto-derived L1–L3: a non-visual or agent
65
+ * reader hears what the author chose to call out first. Provenance-aware —
66
+ * an AI- or watcher-authored note is qualified as such.
67
+ */
68
+ annotations?: string;
69
+ }
70
+ export interface DescribeChartOptions {
71
+ /**
72
+ * Which semantic levels to include. Default ["l1","l2","l3"]. L4 is appended
73
+ * automatically when `capability` (or `capability.act`) is provided and
74
+ * `levels` is left at the default; pass `levels` explicitly to override.
75
+ */
76
+ levels?: DescribeLevel[];
77
+ /** Locale for number formatting. Default "en". */
78
+ locale?: string;
79
+ /**
80
+ * Intent context that powers the L4 illocutionary sentence — a chart's
81
+ * capability descriptor or a resolved {@link DescribeCapabilityContext}.
82
+ * Closes the L1–L3 → L4 gap by joining the *production*-side intent metadata
83
+ * (which already lives in each `*.capability.ts`) to the *reception*-side
84
+ * description.
85
+ */
86
+ capability?: ChartCapability | DescribeCapabilityContext;
87
+ /**
88
+ * Audience profile — tunes the L4 sentence for reception. When the chart's
89
+ * familiarity for this audience is low, L4 appends a brief orienting nudge so
90
+ * an unfamiliar reader leans on the description.
91
+ */
92
+ audience?: AudienceProfile;
93
+ }
94
+ /** The communicative act a built-in intent implies, or undefined if unknown. */
95
+ export declare function communicativeActForIntent(intent: IntentId): CommunicativeAct | undefined;
96
+ /**
97
+ * Resolve the communicative act for a chart from (in priority order) an explicit
98
+ * act, the dominant resolved intent, the declared family, or the component's own
99
+ * family classification. Returns undefined only when nothing identifies it.
100
+ */
101
+ export declare function resolveCommunicativeAct(component: string, context: ChartCapability | DescribeCapabilityContext | undefined): CommunicativeAct | undefined;
102
+ /** Build a number formatter — compact (6.5M) for large magnitudes, plain
103
+ * otherwise. Exported so the navigation tree formats values identically. */
104
+ export declare function chartValueFormatter(locale?: string): (n: number) => string;
105
+ /**
106
+ * One human phrase for a single annotation — its kind (provenance-qualified),
107
+ * plus its label if it has one: `an AI-suggested callout labeled "Peak"`.
108
+ * Exported so the navigation tree (`buildNavigationTree`) labels its annotation
109
+ * nodes with the same vocabulary the prose description uses — tree and prose
110
+ * speak the same language. Editorial status is *not* included here (it would
111
+ * change the prose sentence); callers that want it append it themselves.
112
+ */
113
+ export declare function annotationPhrase(ann: Datum): string;
114
+ export declare function describeChart(component: string, props: Datum, options?: DescribeChartOptions): DescribeChartResult;
@@ -0,0 +1,51 @@
1
+ import type { ChartDataProfile, FieldKind } from "./chartCapabilityTypes";
2
+ export type PrimaryRole = "x" | "y" | "size" | "category" | "series" | "time";
3
+ export interface FieldTypeChange {
4
+ field: string;
5
+ from: FieldKind | "unknown";
6
+ to: FieldKind | "unknown";
7
+ }
8
+ export interface PrimaryRoleChange {
9
+ role: PrimaryRole;
10
+ from: string | undefined;
11
+ to: string | undefined;
12
+ }
13
+ export interface ProfileDiff {
14
+ /** Row count change (b.rowCount - a.rowCount). */
15
+ rowCountChange: number;
16
+ /** Fields present in b but not in a. */
17
+ added: ReadonlyArray<string>;
18
+ /** Fields present in a but not in b. */
19
+ removed: ReadonlyArray<string>;
20
+ /** Fields whose inferred type changed. */
21
+ typeChanges: ReadonlyArray<FieldTypeChange>;
22
+ /** Primary role re-assignments (e.g. x switched from "month" to "date"). */
23
+ primaryChanges: ReadonlyArray<PrimaryRoleChange>;
24
+ /** Suggestion components that fit a but not b. */
25
+ becameUnfit: ReadonlyArray<string>;
26
+ /** Suggestion components that fit b but not a. */
27
+ becameFit: ReadonlyArray<string>;
28
+ /** True when no observable change was detected. */
29
+ unchanged: boolean;
30
+ }
31
+ /**
32
+ * Compare two profiles and report what changed plus how the change affects
33
+ * chart suitability. Useful for:
34
+ *
35
+ * • "Why does my dashboard look different after the data refreshed?"
36
+ * • Editor warnings when a CSV upload would change the visible charts.
37
+ * • CI checks that flag when a fixture migration affects descriptor coverage.
38
+ *
39
+ * Doesn't compute *which suggestions ranked first* (that requires intent +
40
+ * full suggestCharts). Reports only structural deltas — added/removed fields,
41
+ * type changes, primary role re-assignments, fit set changes.
42
+ *
43
+ * @example
44
+ * const a = profileData(yesterdaysData)
45
+ * const b = profileData(todaysData)
46
+ * const diff = diffProfile(a, b)
47
+ * if (diff.becameUnfit.length) {
48
+ * console.warn(`These charts no longer fit: ${diff.becameUnfit.join(", ")}`)
49
+ * }
50
+ */
51
+ export declare function diffProfile(a: ChartDataProfile, b: ChartDataProfile): ProfileDiff;
@@ -0,0 +1,24 @@
1
+ import type { IntentId } from "./intents";
2
+ export interface InferIntentResult {
3
+ intent: IntentId;
4
+ /** 1..5 score for ranking ties. Higher = stronger match. */
5
+ confidence: number;
6
+ /** Other plausible intents, sorted by confidence. */
7
+ alternates: ReadonlyArray<{
8
+ intent: IntentId;
9
+ confidence: number;
10
+ }>;
11
+ }
12
+ /**
13
+ * Map a natural-language query to a built-in intent. Returns `null` when no
14
+ * pattern matches with meaningful confidence.
15
+ *
16
+ * @example
17
+ * inferIntent("when did revenue peak?")
18
+ * // → { intent: "outlier-detection", confidence: 4, alternates: [] }
19
+ * inferIntent("show me the trend over time")
20
+ * // → { intent: "trend", confidence: 4, alternates: [] }
21
+ * inferIntent("hello")
22
+ * // → null
23
+ */
24
+ export declare function inferIntent(query: string): InferIntentResult | null;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Canonical intent taxonomy for chart suggestion / interrogation.
3
+ *
4
+ * An "intent" is what the user is trying to *see* in the data. Charts declare how
5
+ * well they serve each intent in their capability descriptor. The suggestion engine
6
+ * filters and ranks by intent.
7
+ *
8
+ * The taxonomy is fixed but extensible: consumers can call `registerIntent` to add
9
+ * domain-specific intents at runtime. The IntentId type stays union-of-known so
10
+ * built-in code remains type-safe; registered intents are addressable as plain strings.
11
+ */
12
+ export type BuiltInIntentId = "trend" | "compare-series" | "compare-categories" | "rank" | "part-to-whole" | "distribution" | "correlation" | "flow" | "hierarchy" | "geo" | "outlier-detection" | "composition-over-time" | "change-detection";
13
+ /**
14
+ * Any intent — built-in or user-registered. Custom intents are plain strings.
15
+ */
16
+ export type IntentId = BuiltInIntentId | (string & {});
17
+ export interface IntentDescriptor {
18
+ id: IntentId;
19
+ label: string;
20
+ description: string;
21
+ /** Soft hint of which chart family typically serves this intent. */
22
+ familyHint?: "time-series" | "categorical" | "distribution" | "relationship" | "flow" | "network" | "hierarchy" | "geo";
23
+ }
24
+ /** Get an intent descriptor by id, or undefined if not registered. */
25
+ export declare function getIntent(id: IntentId): IntentDescriptor | undefined;
26
+ /** All currently-registered intents (built-in + user-added). */
27
+ export declare function listIntents(): IntentDescriptor[];
28
+ /**
29
+ * Register a custom intent at runtime. Idempotent — re-registering with the same id
30
+ * replaces the descriptor.
31
+ */
32
+ export declare function registerIntent(intent: IntentDescriptor): void;
33
+ /** Sentinel set used by capability authors to opt out of an intent without misspelling. */
34
+ export declare const BUILT_IN_INTENT_IDS: ReadonlySet<BuiltInIntentId>;
@@ -0,0 +1,45 @@
1
+ import type { Datum } from "../charts/shared/datumTypes";
2
+ /**
3
+ * buildNavigationTree — turn a chart config into a structured, labeled
4
+ * navigation tree (chart → axes/series → data points), following the Olli /
5
+ * Data Navigator model: a navigable *structure*, uncoupled from how the chart
6
+ * is rendered (canvas, SVG, image). A screen-reader user descends the tree —
7
+ * "Series sales" → "point 3 of 9: March, 6,800" — with spoken structural
8
+ * context at each level, instead of wading through a flat point list.
9
+ *
10
+ * Pure and SSR-safe. Composes `describeChart()` for node labels so the tree and
11
+ * the prose description speak the same language. Rendered by `AccessibleNavTree`
12
+ * and surfaced as the opt-in ChartContainer `navigable` affordance.
13
+ */
14
+ export type NavTreeRole = "chart" | "axis" | "series" | "datum" | "annotation";
15
+ export interface NavTreeNode {
16
+ /** Stable id within the tree. */
17
+ id: string;
18
+ role: NavTreeRole;
19
+ /** What assistive tech announces for this node. */
20
+ label: string;
21
+ /** 1-based depth (maps to aria-level). */
22
+ level: number;
23
+ /** Measure value, for datum leaves. */
24
+ value?: number;
25
+ /** Raw datum, for datum leaves. */
26
+ datum?: Datum | null;
27
+ children?: NavTreeNode[];
28
+ }
29
+ export interface BuildNavigationTreeOptions {
30
+ /** Cap leaves per branch (keeps a 50k-row chart from building a giant tree). Default 200. */
31
+ maxLeaves?: number;
32
+ locale?: string;
33
+ }
34
+ /**
35
+ * Build a structured navigation tree for a chart config. Full trees for XY,
36
+ * bar, part-to-whole, and distribution families; for everything else (network,
37
+ * hierarchy, geo, single value) it returns a root-only node with an L1 label
38
+ * rather than inventing a structure.
39
+ */
40
+ export declare function buildNavigationTree(component: string, props: Datum, options?: BuildNavigationTreeOptions): NavTreeNode;
41
+ /** Flatten a tree to its visible nodes given a set of expanded node ids, in DFS
42
+ * order. Used by the renderer for roving-tabindex keyboard navigation. */
43
+ export declare function flattenVisible(root: NavTreeNode, expanded: Set<string>): NavTreeNode[];
44
+ /** Total descendant + self count — handy for tests and summaries. */
45
+ export declare function countNodes(root: NavTreeNode): number;
@@ -0,0 +1,16 @@
1
+ import type { Datum } from "../charts/shared/datumTypes";
2
+ import type { ChartDataProfile } from "./chartCapabilityTypes";
3
+ export interface ProfileDataOptions {
4
+ /** If you have access to the raw input (which might be {nodes, edges} or GeoJSON), pass it for structure detection. */
5
+ rawInput?: unknown;
6
+ /** Override the field used as the primary series, useful when the heuristic guesses wrong. */
7
+ seriesField?: string;
8
+ }
9
+ /**
10
+ * Build a ChartDataProfile from row data. Extends DataSummary with shape inference —
11
+ * candidate fields per role, distinct counts, monotonicity, and structure detection.
12
+ *
13
+ * Designed to be called once per dataset; the result is what `suggestCharts` and
14
+ * capability evaluators consume.
15
+ */
16
+ export declare function profileData(data: ReadonlyArray<Datum> | null | undefined, options?: ProfileDataOptions): ChartDataProfile;
@@ -0,0 +1,2 @@
1
+ import type { ScorecardFixture } from "./qualityScorecard";
2
+ export declare const CANONICAL_FIXTURES: ReadonlyArray<ScorecardFixture>;