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
@@ -2,7 +2,7 @@
2
2
 
3
3
  <!-- semiotic-bundle-sizes:start -->
4
4
  <!-- Auto-generated by scripts/sync-bundle-sizes.mjs — do not edit by hand. -->
5
- **Use sub-path imports** — `semiotic/xy` (85KB gz), `semiotic/ordinal` (69KB gz), `semiotic/network` (63KB gz), `semiotic/geo` (52KB gz), `semiotic/realtime` (90KB gz), `semiotic/server` (122KB gz), `semiotic/utils` (22KB gz), `semiotic/recipes` (5KB gz), `semiotic/themes` (4KB gz), `semiotic/data` (3KB gz), `semiotic/ai` (189KB gz). Full `semiotic` is 188KB gz.
5
+ **Use sub-path imports** — `semiotic/xy` (90KB gz), `semiotic/ordinal` (74KB gz), `semiotic/network` (68KB gz), `semiotic/geo` (55KB gz), `semiotic/realtime` (95KB gz), `semiotic/server` (127KB gz), `semiotic/utils` (37KB gz), `semiotic/recipes` (9KB gz), `semiotic/themes` (4KB gz), `semiotic/data` (3KB gz), `semiotic/value` (6KB gz), `semiotic/ai` (246KB gz). Full `semiotic` is 203KB gz.
6
6
  <!-- semiotic-bundle-sizes:end -->
7
7
 
8
8
  ## Flat Array Data (`data: object[]`)
@@ -84,12 +84,15 @@ Callback receiving `ChartObservation`: `{ type: "hover"|"click"|"brush"|"selecti
84
84
  ### emphasis
85
85
  `emphasis="primary"` makes a chart span two columns inside a `ChartGrid`.
86
86
 
87
- ## Annotations (XY and ordinal charts)
87
+ ## Annotations (all chart families)
88
88
  - `annotations={[{ type: "y-threshold", value: 200, label: "SLA limit", color: "#e45050", labelPosition: "right" }]}` — horizontal reference line (works on XY and vertical ordinal charts). `labelPosition`: "left"|"center"|"right"
89
89
  - `annotations={[{ type: "x-threshold", value: 50, label: "Cutoff", labelPosition: "top" }]}` — vertical reference line. `labelPosition`: "top"|"center"|"bottom"
90
+ - `annotations={[{ type: "callout-circle", x: 5, y: 20, label: "Peak", radius: 12 }]}` — data-bound callout; use `callout-rect` with `width`/`height` for a rectangular subject
90
91
  - `annotations={[{ type: "category-highlight", category: "Q3 2024", color: "#4589ff", opacity: 0.15 }]}` — highlight a category column/row in ordinal charts
91
92
  - `annotations={[{ type: "widget", time: 42, latency: 850, dy: -10, content: <span>Alert</span> }]}` — place React element at data coordinates
92
93
  - `annotations={[{ type: "enclose", coordinates: [datum1, datum2], label: "Cluster" }]}` — circle enclosing data points
94
+ - `autoPlaceAnnotations={{ density: true, progressiveDisclosure: true, redundantCues: true }}` — opt-in placement, clutter management, and non-color association support
95
+ - Annotation metadata: `emphasis`, `defensive`, `provenance`, and `lifecycle`; use `applyAnnotationLifecycle`, `applyAnnotationStatus`, and `filterAnnotationsByStatus` from `semiotic/ai`
93
96
 
94
97
  ## Theming & Brand Styling
95
98
  All charts respond to CSS custom properties on any ancestor:
@@ -0,0 +1,25 @@
1
+ import { type NavTreeNode } from "./ai/navigationTree";
2
+ export interface AccessibleNavTreeProps {
3
+ tree: NavTreeNode;
4
+ /** Accessible name for the tree. */
5
+ label?: string;
6
+ /** Show the tree visibly (default: screen-reader-only). */
7
+ visible?: boolean;
8
+ className?: string;
9
+ /** Fired when the active node changes (e.g. to highlight the matching mark). */
10
+ onActiveChange?: (node: NavTreeNode) => void;
11
+ /**
12
+ * Controlled active node id. When provided, the parent owns the active node
13
+ * (e.g. `useNavigationSync` driving it from the chart's hover). The tree
14
+ * auto-expands the path to a controlled active node so it stays visible.
15
+ */
16
+ activeId?: string;
17
+ /**
18
+ * `chartId` of the chart this tree describes. Correlates the reception
19
+ * telemetry the tree emits (`nav-node-focused` / `nav-branch-expanded`
20
+ * conversation-arc events) back to the chart. Events are only recorded while
21
+ * the conversation-arc store is enabled — zero-overhead otherwise.
22
+ */
23
+ chartId?: string;
24
+ }
25
+ export declare function AccessibleNavTree({ tree, label, visible, className, onActiveChange, activeId: controlledActiveId, chartId }: AccessibleNavTreeProps): import("react/jsx-runtime").JSX.Element;
@@ -1,11 +1,41 @@
1
1
  import * as React from "react";
2
+ type AnnotationEventHandlers = Record<string, (e: React.SyntheticEvent) => void>;
3
+ type AnnotationNote = {
4
+ label?: string;
5
+ title?: string;
6
+ wrap?: number;
7
+ orientation?: string;
8
+ align?: string;
9
+ noWrap?: boolean;
10
+ };
11
+ type AnnotationConnector = {
12
+ end?: "arrow";
13
+ type?: "line" | "curve";
14
+ curve?: number;
15
+ };
16
+ type AnnotationSubject = {
17
+ radius?: number;
18
+ radiusPadding?: number;
19
+ width?: number;
20
+ height?: number;
21
+ custom?: React.ReactElement | React.ReactElement[];
22
+ x?: number;
23
+ y?: number;
24
+ x1?: number;
25
+ x2?: number;
26
+ y1?: number;
27
+ y2?: number;
28
+ type?: string;
29
+ depth?: number;
30
+ [key: string]: unknown;
31
+ };
2
32
  /** Props for the single-annotation renderer. Consumed only by `SemioticAnnotation`
3
33
  * below; the broader annotation API flows through the frame-level `annotations`
4
34
  * array and its `svgAnnotationRules` hook. */
5
35
  export interface AnnotationProps {
6
36
  noteData: {
7
- eventListeners?: Record<string, (e: React.SyntheticEvent) => void>;
8
- events?: Record<string, (e: React.SyntheticEvent) => void>;
37
+ eventListeners?: AnnotationEventHandlers;
38
+ events?: AnnotationEventHandlers;
9
39
  type: string;
10
40
  screenCoordinates?: number[][];
11
41
  /** When truthy, `screenCoordinates` is read as a sequence of anchor points
@@ -19,25 +49,21 @@ export interface AnnotationProps {
19
49
  ny?: number;
20
50
  dx?: number;
21
51
  dy?: number;
22
- note: {
23
- label?: string;
24
- title?: string;
25
- wrap?: number;
26
- orientation?: string;
27
- align?: string;
28
- noWrap?: boolean;
29
- };
52
+ note: AnnotationNote;
30
53
  i?: number;
31
54
  fixedPosition?: boolean;
32
55
  label?: string;
33
- connector?: {
34
- end?: "arrow";
35
- };
36
- subject?: Record<string, unknown>;
56
+ connector?: AnnotationConnector;
57
+ subject?: AnnotationSubject;
37
58
  color?: string;
38
59
  className?: string;
39
60
  disable?: string[];
61
+ /** SVG opacity cascaded to every stroked/filled child of the annotation. */
62
+ opacity?: number;
63
+ /** SVG stroke-dasharray cascaded to every stroked child of the annotation. */
64
+ strokeDasharray?: string;
40
65
  [key: string]: unknown;
41
66
  };
42
67
  }
43
68
  export default function SemioticAnnotation(props: AnnotationProps): import("react/jsx-runtime").JSX.Element;
69
+ export {};
@@ -1,5 +1,6 @@
1
1
  import * as React from "react";
2
2
  import type { ChartConfig, CopyFormat } from "./export/chartConfig";
3
+ import { type DescribeLevel } from "./ai/describeChart";
3
4
  export interface ChartContainerProps {
4
5
  /** Chart title */
5
6
  title?: string;
@@ -26,8 +27,37 @@ export interface ChartContainerProps {
26
27
  /** Enable "Data Summary" action button — shows statistical summary + sample rows */
27
28
  dataSummary?: boolean;
28
29
  };
29
- /** Chart configuration for serialization. Enables the "Copy Config" toolbar action. */
30
- chartConfig?: ChartConfig;
30
+ /**
31
+ * Chart configuration. Enables the "Copy Config" toolbar action and the
32
+ * `describe`/`navigable` a11y affordances. Only `component` and `props` are
33
+ * required — the `version`/`createdAt` serialization metadata is optional
34
+ * here and synthesized when copying.
35
+ */
36
+ chartConfig?: Omit<ChartConfig, "version" | "createdAt"> & Partial<Pick<ChartConfig, "version" | "createdAt">>;
37
+ /**
38
+ * Auto-generate a layered (L1–L3) natural-language description from
39
+ * `chartConfig` and expose it at the container level — the opt-in path to a
40
+ * fuller accessible reading than the bare chart's terse aria-label. Requires
41
+ * `chartConfig`. `true` renders a screen-reader-only note; pass
42
+ * `{ visible: true }` to also show it as a visible caption, or `{ levels }`
43
+ * to choose verbosity. Backed by `describeChart()`.
44
+ */
45
+ describe?: boolean | {
46
+ levels?: DescribeLevel[];
47
+ visible?: boolean;
48
+ };
49
+ /**
50
+ * Mount a structured, screen-reader-navigable tree of the chart (chart →
51
+ * axes/series → data points), built from `chartConfig` — the Olli /
52
+ * Data Navigator model, as an opt-in at the container layer. Requires
53
+ * `chartConfig`. `true` renders it screen-reader-only; `{ visible: true }`
54
+ * shows it; `{ maxLeaves }` caps leaves per branch. Backed by
55
+ * `buildNavigationTree()` + `AccessibleNavTree`.
56
+ */
57
+ navigable?: boolean | {
58
+ visible?: boolean;
59
+ maxLeaves?: number;
60
+ };
31
61
  /** Additional controls rendered in the toolbar after built-in actions */
32
62
  controls?: React.ReactNode;
33
63
  /** Loading state — shows skeleton placeholder */
@@ -0,0 +1,349 @@
1
+ /**
2
+ * Where an annotation came from and how confident we should be in it.
3
+ * Lives on `annotation.provenance`.
4
+ */
5
+ export interface AnnotationProvenance {
6
+ /**
7
+ * Display name (or stable id) for who created the annotation — a
8
+ * person, agent, or watcher. Together with `authorKind` this expresses
9
+ * IDID §8's structured `author: { kind, id }`: `authorKind` is the
10
+ * actor category, `author` is the name/id.
11
+ */
12
+ author?: string;
13
+ /**
14
+ * Actor category — *who* created the annotation. IDID §8's
15
+ * `author.kind`. Distinct from `basis` (*how* it was derived) and from
16
+ * the coarser `source`. Open union; consumers may extend.
17
+ */
18
+ authorKind?: AnnotationActorKind;
19
+ /**
20
+ * Origin category. Recognized values are not exhaustive; consumers
21
+ * may extend with their own source labels. Coarser than the
22
+ * `authorKind` / `basis` pair — kept for back-compat and as a single
23
+ * convenience label when the finer split isn't needed.
24
+ */
25
+ source?: AnnotationSource;
26
+ /**
27
+ * Evidence type — *how* the annotation's claim was derived
28
+ * (a hand note, a statistical test, a rule, an LLM inference, an
29
+ * external source). IDID §8's `basis`. Distinct from `authorKind`
30
+ * (the actor) and `source` (the coarse origin): a `"human"` author can
31
+ * relay a `"statistical-test"` basis. Lets a reader weight a note by
32
+ * the strength of its evidence, not just who left it.
33
+ */
34
+ basis?: AnnotationBasis;
35
+ /**
36
+ * Confidence in the assertion, 0–1. `1` is a hand-placed user
37
+ * annotation; LLM-suggested annotations typically land below 0.8.
38
+ */
39
+ confidence?: number;
40
+ /** ISO 8601 timestamp marking when the annotation was created. */
41
+ createdAt?: string;
42
+ /**
43
+ * Identifier of the data snapshot the annotation was made against
44
+ * (IDID §8's `dataVersion`). Lets a consumer tell "this note was
45
+ * written about last week's data" from "this note still tracks the
46
+ * current data," independent of wall-clock freshness.
47
+ */
48
+ dataVersion?: string;
49
+ /**
50
+ * Stable, opaque identifier that survives data refresh and chart
51
+ * recreation. Used by the `"semantic"` anchor-resolution work to
52
+ * re-locate "the Q3 spike" after new data arrives, and as the target
53
+ * of another annotation's `lifecycle.supersedes`.
54
+ */
55
+ stableId?: string;
56
+ }
57
+ /**
58
+ * Actor category for an annotation — *who* created it. IDID §8 models
59
+ * this as `author.kind`. Open string union: `"system"` covers
60
+ * non-watcher automated placement, and consumers may pass any other
61
+ * label (it is preserved).
62
+ */
63
+ export type AnnotationActorKind = "human" | "agent" | "watcher" | "system" | (string & {});
64
+ /**
65
+ * Evidence type for an annotation — *how* its claim was derived. IDID
66
+ * §8's `basis`. Open string union so consumers can add evidence kinds
67
+ * (e.g. `"forecast"`, `"manual-review"`) without a type change.
68
+ */
69
+ export type AnnotationBasis = "human-note" | "statistical-test" | "rule" | "llm-inference" | "external-source" | "computed" | (string & {});
70
+ /**
71
+ * Recognized provenance sources. Open string union — consumers may
72
+ * pass any other label and it will be preserved.
73
+ */
74
+ export type AnnotationSource = "user" | "ai" | "agent" | "import" | "computed" | "system" | (string & {});
75
+ /**
76
+ * How an annotation ages relative to the chart's current data extent.
77
+ * Default visual treatment (defined in M2): `aging` dims, `stale`
78
+ * draws a dashed border, `expired` is hidden unless
79
+ * `showExpiredAnnotations` is on.
80
+ */
81
+ export type AnnotationFreshness = LifecycleBand;
82
+ import type { AnnotationAnchor } from "../realtime/types";
83
+ export type { AnnotationAnchor } from "../realtime/types";
84
+ import type { LifecycleBand, LifecycleBandThresholds } from "../realtime/lifecycleBands";
85
+ export { bandFromAge, DEFAULT_LIFECYCLE_THRESHOLDS } from "../realtime/lifecycleBands";
86
+ export type { LifecycleBand, LifecycleBandThresholds } from "../realtime/lifecycleBands";
87
+ /**
88
+ * Editorial standing of an annotation in a multiplayer conversation —
89
+ * is the note still believed? IDID §8's `status`. Orthogonal to the
90
+ * temporal `freshness` band: a note can be fresh-but-`disputed` or
91
+ * stale-but-`accepted`. Closed union — these four are the editorial
92
+ * state machine the editorial-lifecycle work drives:
93
+ *
94
+ * - `"proposed"` — placed but unreviewed (e.g. a watcher's auto-note).
95
+ * - `"accepted"` — confirmed by a human or agent.
96
+ * - `"disputed"` — contested; under review.
97
+ * - `"retracted"` — withdrawn; treat like an expired note.
98
+ */
99
+ export type AnnotationStatus = "proposed" | "accepted" | "disputed" | "retracted";
100
+ /**
101
+ * Lifecycle state for an annotation. Lives on `annotation.lifecycle`.
102
+ *
103
+ * Two orthogonal axes: the **temporal** band (`freshness`, derived from
104
+ * `createdAt` + `ttlHint`) and the **editorial** state (`status`,
105
+ * driven by the multiplayer accept/dispute/retract flow). `supersedes`
106
+ * links a revision to the note it replaces.
107
+ */
108
+ export interface AnnotationLifecycle {
109
+ /**
110
+ * Current freshness band. When omitted, `computeAnnotationFreshness`
111
+ * derives it from `ttlHint` and the data's current temporal extent.
112
+ */
113
+ freshness?: AnnotationFreshness;
114
+ /**
115
+ * Editorial standing (IDID §8's `status`). Set by the multiplayer
116
+ * accept/dispute/retract flow; orthogonal to `freshness`. When
117
+ * omitted, the annotation is treated as unconditionally shown (the
118
+ * pre-editorial-lifecycle behavior). Status-driven visual treatment
119
+ * is owed alongside the editorial-lifecycle work — the field ships
120
+ * first so it can be stamped now.
121
+ */
122
+ status?: AnnotationStatus;
123
+ /**
124
+ * `provenance.stableId` of the annotation this one replaces (IDID
125
+ * §8's `supersedes`). Forms a revision chain so a reader can trace how
126
+ * an interpretation changed; the superseded note is typically hidden
127
+ * once its replacement is `accepted`.
128
+ */
129
+ supersedes?: string;
130
+ /**
131
+ * How long this annotation should be considered fresh. Either an
132
+ * ISO 8601 duration string (`"PT24H"`, `"P7D"`) or a number of
133
+ * milliseconds. The freshness computation walks `fresh → aging
134
+ * → stale → expired` as the chart's "now" advances past
135
+ * `createdAt + ttlHint`.
136
+ */
137
+ ttlHint?: string | number;
138
+ /** Anchor resolution strategy. Defaults to `"fixed"` when omitted. */
139
+ anchor?: AnnotationAnchor;
140
+ }
141
+ /**
142
+ * Carries the new optional blocks onto whatever annotation type the
143
+ * chart accepts. Use as `Annotated<typeof myAnnotation>` for explicit
144
+ * typing, or call `withProvenance()` for inline authoring.
145
+ */
146
+ export type Annotated<T> = T & {
147
+ provenance?: AnnotationProvenance;
148
+ lifecycle?: AnnotationLifecycle;
149
+ };
150
+ /**
151
+ * Convenience builder — attaches provenance + lifecycle blocks to an
152
+ * annotation without disturbing its existing fields. Returns a new
153
+ * object; does not mutate. Pure function, safe to call in SSR.
154
+ *
155
+ * ```ts
156
+ * withProvenance(
157
+ * { type: "y-threshold", value: 100, label: "SLA breach" },
158
+ * {
159
+ * provenance: { author: "alice", source: "user", createdAt: "2026-05-20T14:00:00Z" },
160
+ * lifecycle: { ttlHint: "P30D", anchor: "semantic" },
161
+ * }
162
+ * )
163
+ * ```
164
+ */
165
+ export declare function withProvenance<T extends object>(annotation: T, blocks: {
166
+ provenance?: AnnotationProvenance;
167
+ lifecycle?: AnnotationLifecycle;
168
+ }): Annotated<T>;
169
+ /**
170
+ * Returns an ISO 8601 wall-clock timestamp suitable for stamping
171
+ * `provenance.createdAt`. Sugar over `new Date().toISOString()`, but
172
+ * named to make intent obvious in streaming consumers: "mark this
173
+ * annotation as created now, so the lifecycle helpers can age it."
174
+ *
175
+ * Pair with `applyAnnotationLifecycle({ dataExtent })` on time-series
176
+ * charts to have annotations age against chart-time rather than
177
+ * wall-clock — the chart's latest data point becomes the "now"
178
+ * reference, and recently-stamped annotations stay fresh for as long
179
+ * as new data is flowing.
180
+ */
181
+ export declare function currentTimestamp(): string;
182
+ /**
183
+ * Stamp an annotation with `provenance.createdAt = currentTimestamp()`
184
+ * (unless it already has a `createdAt`) and optional additional
185
+ * provenance fields. Intended for the streaming "I'm marking the
186
+ * latest data point" pattern, where the annotation's age should be
187
+ * measured from when the consumer added it.
188
+ *
189
+ * Equivalent to:
190
+ * ```ts
191
+ * withProvenance(ann, {
192
+ * provenance: { createdAt: currentTimestamp(), ...rest },
193
+ * lifecycle: ann.lifecycle,
194
+ * })
195
+ * ```
196
+ * — but reads cleaner at call sites and preserves any existing
197
+ * `createdAt`.
198
+ */
199
+ export declare function withCurrentProvenance<T extends object>(annotation: T, rest?: Omit<AnnotationProvenance, "createdAt"> & {
200
+ createdAt?: string;
201
+ }): Annotated<T>;
202
+ /**
203
+ * Options accepted by `computeAnnotationFreshness` and
204
+ * `applyAnnotationLifecycle`.
205
+ */
206
+ export interface ComputeAnnotationFreshnessOptions {
207
+ /**
208
+ * "Now" reference for age calculations. Number is epoch ms; string is
209
+ * any value `Date.parse` accepts. When omitted, defaults to the max
210
+ * of `dataExtent`, falling back to `Date.now()`.
211
+ */
212
+ now?: number | Date | string;
213
+ /**
214
+ * The chart's current temporal extent — typically `[oldest, newest]`
215
+ * x values. Used to derive a sensible "now" for streaming charts
216
+ * (where wall-clock time and the data's notion of "now" can drift).
217
+ */
218
+ dataExtent?: ReadonlyArray<number | Date | string> | {
219
+ min: number | Date | string;
220
+ max: number | Date | string;
221
+ };
222
+ /**
223
+ * Override the default age thresholds. Each value is a multiplier of
224
+ * `ttlHint`. Defaults: aging at 1×, stale at 1.5×, expired at 3×.
225
+ * Same shape as `LifecycleBandThresholds` from the shared primitive.
226
+ */
227
+ thresholds?: LifecycleBandThresholds;
228
+ }
229
+ /**
230
+ * Classify an annotation into a freshness band. Exported for tests and
231
+ * for consumers that want the per-annotation band without rebuilding
232
+ * the entire array.
233
+ *
234
+ * Returns the annotation's existing `lifecycle.freshness` verbatim if
235
+ * the annotation lacks the `createdAt` or `ttlHint` needed to compute
236
+ * a band — i.e. an explicit assignment always wins over inference.
237
+ */
238
+ export declare function annotationFreshnessFor<T>(annotation: Annotated<T>, nowMs: number, thresholds?: LifecycleBandThresholds): AnnotationFreshness;
239
+ /**
240
+ * Walk an annotations array and populate `lifecycle.freshness` on each
241
+ * entry from its `provenance.createdAt` and `lifecycle.ttlHint`.
242
+ *
243
+ * Pure function — returns a new array; does not mutate input. Safe
244
+ * to call in SSR. Annotations missing the inputs needed to compute a
245
+ * band keep whatever `lifecycle.freshness` they already had (so an
246
+ * explicit assignment always wins).
247
+ *
248
+ * For non-temporal charts, pass `now` explicitly. For streaming /
249
+ * time-series charts, pass `dataExtent` — the helper picks the latest
250
+ * value as "now" so freshness tracks chart-time, not wall-clock.
251
+ */
252
+ export declare function computeAnnotationFreshness<T>(annotations: ReadonlyArray<Annotated<T>>, options?: ComputeAnnotationFreshnessOptions): Annotated<T>[];
253
+ /**
254
+ * Style overrides per freshness band. Each map is partial — bands not
255
+ * present fall back to the defaults below. `null` for a value removes
256
+ * the default rather than applying it (e.g. `{ opacity: { aging: null } }`
257
+ * disables dimming aging annotations).
258
+ */
259
+ export interface AnnotationLifecycleTreatment {
260
+ opacity?: Partial<Record<AnnotationFreshness, number | null>>;
261
+ strokeDasharray?: Partial<Record<AnnotationFreshness, string | null>>;
262
+ /** Suffix appended to `label` for that band. Default suffixes are off. */
263
+ labelSuffix?: Partial<Record<AnnotationFreshness, string>>;
264
+ /**
265
+ * When true, expired annotations stay in the returned array (with
266
+ * the expired treatment applied). When false (default), expired
267
+ * annotations are filtered out — matching the "hidden by default"
268
+ * contract from the talk-readiness roadmap.
269
+ */
270
+ showExpiredAnnotations?: boolean;
271
+ }
272
+ export type ApplyAnnotationLifecycleOptions = ComputeAnnotationFreshnessOptions & AnnotationLifecycleTreatment;
273
+ /**
274
+ * Compute freshness and apply the default visual treatment in one pass.
275
+ *
276
+ * Behavior per band (overridable via options):
277
+ * - **fresh** — no change
278
+ * - **aging** — `opacity` 0.55
279
+ * - **stale** — `opacity` 0.35, `strokeDasharray` `"4 4"` (cascades
280
+ * through the annotation's stroked children)
281
+ * - **expired** — filtered out by default; pass
282
+ * `showExpiredAnnotations: true` to keep them with `opacity` 0.2 and
283
+ * `strokeDasharray` `"2 4"`
284
+ *
285
+ * Treatment composes cleanly with annotations that already carry their
286
+ * own `color` / `opacity` — explicit fields on the annotation win,
287
+ * the treatment only fills in what isn't already set.
288
+ */
289
+ export declare function applyAnnotationLifecycle<T>(annotations: ReadonlyArray<Annotated<T>>, options?: ApplyAnnotationLifecycleOptions): Annotated<T>[];
290
+ /**
291
+ * Style overrides per editorial status. Each map is partial — statuses not
292
+ * present fall back to the defaults below. `null` for a value removes the
293
+ * default rather than applying it.
294
+ */
295
+ export interface AnnotationStatusVisibility {
296
+ /**
297
+ * Keep `retracted` annotations instead of filtering them out. Default false
298
+ * — retracted is hidden like `expired`.
299
+ */
300
+ showRetractedAnnotations?: boolean;
301
+ /**
302
+ * Keep an annotation that another *present* note supersedes. Default false
303
+ * — a superseded note is hidden once its replacement is in the array.
304
+ */
305
+ showSupersededAnnotations?: boolean;
306
+ }
307
+ export interface AnnotationStatusTreatment extends AnnotationStatusVisibility {
308
+ /**
309
+ * Opacity *factor* per status, multiplied into any existing opacity so it
310
+ * composes with the freshness treatment (run `applyAnnotationLifecycle`
311
+ * first, then this). `null` disables the factor for that status.
312
+ */
313
+ opacity?: Partial<Record<AnnotationStatus, number | null>>;
314
+ strokeDasharray?: Partial<Record<AnnotationStatus, string | null>>;
315
+ /**
316
+ * Suffix appended to a string `label` for that status — the `disputed`
317
+ * default `" (?)"` is the query affordance the strategy calls for.
318
+ */
319
+ labelSuffix?: Partial<Record<AnnotationStatus, string>>;
320
+ }
321
+ /**
322
+ * Apply the default editorial visibility contract without changing annotation
323
+ * styling. Retracted notes and notes replaced by a present revision are hidden
324
+ * unless explicitly requested. Shared by visual treatment, chart descriptions,
325
+ * and navigation trees so they expose the same current set.
326
+ */
327
+ export declare function filterAnnotationsByStatus<T>(annotations: ReadonlyArray<Annotated<T>>, options?: AnnotationStatusVisibility): Annotated<T>[];
328
+ /**
329
+ * Apply the editorial-status visual treatment (M7) — the orthogonal companion
330
+ * to {@link applyAnnotationLifecycle}'s temporal-freshness treatment. The two
331
+ * compose (a note can be stale-and-disputed); run freshness first, then this.
332
+ *
333
+ * Per status (overridable via options):
334
+ * - **accepted** — no change (full weight).
335
+ * - **proposed** — `opacity` ×0.7, dashed `"3 3"`, `label` suffix `" (proposed)"`.
336
+ * An unreviewed (e.g. watcher) note reads provisionally.
337
+ * - **disputed** — `opacity` ×0.7, dashed `"2 3"`, `label` suffix `" (?)"`.
338
+ * The suffix is the query affordance: a contested note announces itself.
339
+ * - **retracted** — filtered out by default (like `expired`); pass
340
+ * `showRetractedAnnotations: true` to keep it at `opacity` ×0.25.
341
+ *
342
+ * Also resolves **supersession**: a note whose `provenance.stableId` is the
343
+ * `lifecycle.supersedes` target of another *present, non-retracted* note is
344
+ * hidden (the revision replaced it), unless `showSupersededAnnotations` is set.
345
+ *
346
+ * Pure — returns a new array; safe in SSR. Opacity is multiplied into any
347
+ * existing value, so it composes with freshness dimming and author-set opacity.
348
+ */
349
+ export declare function applyAnnotationStatus<T>(annotations: ReadonlyArray<Annotated<T>>, options?: AnnotationStatusTreatment): Annotated<T>[];
@@ -0,0 +1,147 @@
1
+ import type { ChartRubric } from "./chartCapabilityTypes";
2
+ import type { AccessibilityAuditResult } from "../charts/shared/auditAccessibility";
3
+ /**
4
+ * The channel an audience receives a chart through. Orthogonal to familiarity:
5
+ * a reader can be highly familiar with a chart type yet unable to *receive* it
6
+ * in their channel (an 8-slice pie is familiar but illegible to a screen
7
+ * reader). Defaults to `"visual"` when unset — no receivability bias applied.
8
+ *
9
+ * • `visual` — sighted reader; the historical default, no bias.
10
+ * • `screen-reader` — non-visual; meaning must survive the data table / nav tree.
11
+ * • `sonified` — audio; density and ordering matter more than color.
12
+ * • `agent` — an LLM reading via the grounding payload; same non-visual
13
+ * "is the meaning recoverable without pixels?" question.
14
+ */
15
+ export type ReceptionModality = "visual" | "screen-reader" | "sonified" | "agent";
16
+ /**
17
+ * A serializable description of who's reading the charts and what the
18
+ * organization is trying to grow.
19
+ *
20
+ * Semiotic does not measure familiarity — it consumes measurements. Orgs
21
+ * produce an AudienceProfile through whatever channel makes sense (surveys,
22
+ * telemetry, manager judgment, training records) and pass it to the
23
+ * suggestion APIs. The library applies the bias and returns rankings that
24
+ * reflect the audience instead of a generic data-literate baseline.
25
+ */
26
+ export interface AudienceProfile {
27
+ /**
28
+ * Display name. Surfaced in suggestion `reasons[]` when a target fires so
29
+ * users can see whose policy is influencing the ranking.
30
+ */
31
+ name?: string;
32
+ /**
33
+ * Per-chart familiarity override (1..5). Replaces the descriptor's
34
+ * `rubric.familiarity`. Charts not listed fall back to the descriptor.
35
+ *
36
+ * @example
37
+ * familiarity: { BarChart: 5, LineChart: 5, PieChart: 4, BoxPlot: 2 }
38
+ */
39
+ familiarity?: Partial<Record<string, number>>;
40
+ /**
41
+ * Adoption targets — which charts the org is trying to grow or reduce.
42
+ * The engine applies a meaningful score bias (±1..3 depending on weight)
43
+ * so growth targets win close calls and decrease targets fall back unless
44
+ * they're the only fit.
45
+ *
46
+ * @example
47
+ * targets: {
48
+ * PieChart: { direction: "decrease", weight: 1 },
49
+ * BoxPlot: { direction: "increase", weight: 2,
50
+ * reason: "we want the team reading distributions, not means" }
51
+ * }
52
+ */
53
+ targets?: Partial<Record<string, AudienceTarget>>;
54
+ /**
55
+ * Controls visibility of stretch picks (unfamiliar-but-relevant charts).
56
+ * 0 — never surface stretches; familiar-only rankings
57
+ * 1 — surface in a separate `stretchSuggestions` list (default when audience set)
58
+ * 2 — same as 1 but lowers the familiarity threshold (≤4) for what counts as stretch,
59
+ * widening the menu
60
+ */
61
+ exposureLevel?: 0 | 1 | 2;
62
+ /**
63
+ * The channel this audience receives charts through. When set to a non-visual
64
+ * modality, `suggestCharts` runs the accessibility audit on each candidate and
65
+ * `applyAudienceBias` down-ranks charts whose meaning doesn't survive that
66
+ * channel (and surfaces the receivability findings as caveats). Unset /
67
+ * `"visual"` keeps the historical behavior — familiarity and targets only.
68
+ * See {@link receivabilityBias}.
69
+ */
70
+ receptionModality?: ReceptionModality;
71
+ }
72
+ export interface AudienceTarget {
73
+ direction: "increase" | "decrease";
74
+ /** 1..3 — controls bias magnitude. Default 1. */
75
+ weight?: number;
76
+ /** Human-readable rationale. Surfaces in suggestion.reasons when the target fires. */
77
+ reason?: string;
78
+ }
79
+ export interface AudienceBiasResult {
80
+ /** Composite score after audience adjustments. Unclamped — can range outside 0..5. */
81
+ score: number;
82
+ /** Effective rubric for the chart after audience overrides. */
83
+ rubric: ChartRubric;
84
+ /** Reason string to append to the suggestion when a target fired. */
85
+ appliedReason?: string;
86
+ /** Reason string to append when a receivability penalty fired (non-visual modality). */
87
+ receivabilityReason?: string;
88
+ }
89
+ export interface ReceivabilitySignal {
90
+ /** Score delta (≤ 0) — the receivability penalty for this channel. */
91
+ delta: number;
92
+ /** One-line reason, present only when a penalty applied. */
93
+ reason?: string;
94
+ /**
95
+ * Caveat messages for the findings that drove the penalty — the receivability
96
+ * slice of the audit, ready to merge into a suggestion's `caveats[]` alongside
97
+ * the perceptual ones (so both channels read from the same array).
98
+ */
99
+ caveats: string[];
100
+ }
101
+ /**
102
+ * Translate an accessibility audit into a receivability penalty for a non-visual
103
+ * channel. Pure. `fail` findings on receivability-critical heuristics weigh most;
104
+ * `warn` findings weigh less; `manual`/`pass`/`not-applicable` never penalize
105
+ * (we don't punish what we can't prove). Penalty is clamped to a −3 floor so it
106
+ * reorders rankings without overriding data-shape correctness.
107
+ *
108
+ * ```ts
109
+ * const audit = auditAccessibility("PieChart", props)
110
+ * const { delta, reason } = receivabilityBias(audit, "screen-reader")
111
+ * ```
112
+ */
113
+ export declare function receivabilityBias(audit: AccessibilityAuditResult, modality: ReceptionModality): ReceivabilitySignal;
114
+ /**
115
+ * Apply an AudienceProfile's bias to a chart's composite score and rubric.
116
+ * Pure function — used by both `suggestCharts` and `suggestStretchCharts`.
117
+ *
118
+ * Two terms compose additively:
119
+ * • Familiarity bias: (audienceFamiliarity − 3) × 0.5
120
+ * — Range ±1.0. At familiarity 5 we add 1.0; at 1 we subtract 1.0.
121
+ * • Target bias: ±1.0 × weight
122
+ * — Range ±3.0 for weight=3. Strong enough to reorder rankings,
123
+ * not so strong that it overrides chart correctness for the data shape.
124
+ *
125
+ * Score is left unclamped so internal sorting reflects the magnitude of bias.
126
+ *
127
+ * A third term — *receivability* — composes in when the audience declares a
128
+ * non-visual `receptionModality` and the caller passes a precomputed
129
+ * {@link ReceivabilitySignal} (from {@link receivabilityBias}). Familiarity and
130
+ * receivability are different axes: a chart can be familiar yet unreceivable in
131
+ * the target channel, and this folds that signal into the same score the
132
+ * recommender ranks by. The caller computes the signal once and reuses it for
133
+ * the suggestion's caveats too, so the audit is scanned a single time per
134
+ * candidate.
135
+ */
136
+ export declare function applyAudienceBias(baseScore: number, baseRubric: ChartRubric, component: string, audience: AudienceProfile | undefined, receivability?: ReceivabilitySignal): AudienceBiasResult;
137
+ /**
138
+ * Resolve the effective familiarity for a chart under an audience. Used by
139
+ * the stretch surface to decide whether a chart qualifies as "unfamiliar."
140
+ */
141
+ export declare function effectiveFamiliarity(component: string, defaultFamiliarity: number, audience: AudienceProfile | undefined): number;
142
+ /**
143
+ * Familiarity threshold for what counts as a "stretch" pick under this audience.
144
+ * Tighter for exposureLevel 1, wider for 2. Returns the highest familiarity a
145
+ * chart can have and still appear in the stretch surface.
146
+ */
147
+ export declare function stretchFamiliarityCeiling(audience: AudienceProfile | undefined): number;