@pond-ts/fit 0.68.0 → 0.70.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.
package/AGENTS.md CHANGED
@@ -60,8 +60,9 @@ const s = TimeSeries.fromJSON({
60
60
  ```
61
61
 
62
62
  Time cells accept ms-since-epoch numbers, `Date`s, or ISO strings **with an
63
- offset** (`…Z`, `…+01:00`). A wall-clock string with no offset throws unless
64
- you pass `parse: { timeZone: 'America/New_York' }`.
63
+ offset** (`…Z`, `…+01:00`). A wall-clock string with no offset is read as
64
+ **UTC** unless you pass `parse: { timeZone: 'America/New_York' }` — it does
65
+ not throw, it silently shifts by the zone's offset.
65
66
 
66
67
  Other doors: `TimeSeries.fromPoints(points)` for wide `{ ts, a, b }` rows,
67
68
  `fromColumns` for struct-of-arrays / `Float64Array`, `fromArrow` for an Arrow
@@ -214,7 +215,8 @@ them; `import { STUDIES } from '@pond-ts/financial/catalog'` lists them at runti
214
215
  event); `align` puts rows on a grid without reducing.
215
216
  3. **`Sequence.every('1M')` for months.** Not fixed-length → use
216
217
  `Sequence.calendar('month', { timeZone })`.
217
- 4. **Wall-clock strings without a zone.** `'2025-01-01T09:00'` throws; add
218
+ 4. **Wall-clock strings without a zone.** `'2025-01-01T09:00'` is read as
219
+ UTC — no error, every instant shifted by your offset. Add
218
220
  `parse: { timeZone }` or use offset strings / ms numbers.
219
221
  5. **Unsorted rows.** The constructor throws and names the row; pass
220
222
  `sort: true` rather than sorting by hand.
@@ -227,6 +229,13 @@ them; `import { STUDIES } from '@pond-ts/financial/catalog'` lists them at runti
227
229
  9. **Reaching for a chart-library adapter first.** If the project uses React,
228
230
  `@pond-ts/charts` consumes the series with no adapter; `toPoints()` is the
229
231
  bridge for other libraries.
232
+ 10. **Aggregating in one zone and charting in another.** `Sequence.calendar`
233
+ defaults to **UTC**; a chart's time axis defaults to the **viewer's**
234
+ zone. Pass the same `timeZone` to both — `Sequence.calendar('day', {
235
+ timeZone })` and `<ChartContainer timeZone={timeZone}>` — and a bucket
236
+ edge and the tick that labels it are one instant. A
237
+ `TradingCalendar.fromRules` carries its zone; `calendar={cal}` renders in
238
+ it with no further wiring.
230
239
 
231
240
  ## Where to read next
232
241
 
package/API.md CHANGED
@@ -45,7 +45,7 @@ next door is the point.
45
45
  | `TimeSeries` | Immutable time-indexed collection, columnar storage | `packages/core/src/batch/time-series.ts` |
46
46
  | `ValueSeries` | Series keyed by a monotonic non-time value axis | `packages/core/src/batch/value-series.ts` |
47
47
  | `PartitionedTimeSeries` | Scoped view for per-partition stateful transforms; `<S, K, By>` — `By` is the partition column names, carried into `aggregate` / `rolling` result types | `packages/core/src/batch/partitioned-time-series.ts` |
48
- | `Sequence` | Infinite grid of time buckets (daily, hourly, every N) | `packages/core/src/sequence/sequence.ts` |
48
+ | `Sequence` | Infinite grid of time buckets: fixed-step (hourly, every N) or calendar (day/week/month/quarter/year in an IANA zone, default UTC) | `packages/core/src/sequence/sequence.ts` |
49
49
  | `BoundedSequence` | Finite ordered list of explicit interval buckets | `packages/core/src/sequence/bounded-sequence.ts` |
50
50
 
51
51
  Static constructors on `TimeSeries`: `fromJSON()` (row tuples/objects),
@@ -99,13 +99,14 @@ Value-axis wire types
99
99
 
100
100
  ### Temporal keys & events
101
101
 
102
- | Export | Purpose | Source |
103
- | ------------- | --------------------------------------------- | -------------------------------------- |
104
- | `Time` | Point-in-time event key | `packages/core/src/core/time.ts` |
105
- | `TimeRange` | Interval event key (start/end) | `packages/core/src/core/time-range.ts` |
106
- | `Interval` | Labeled time-interval event key | `packages/core/src/core/interval.ts` |
107
- | `Event` | Immutable event: temporal key + typed payload | `packages/core/src/core/event.ts` |
108
- | `toTimeRange` | Coerce temporal values to `TimeRange` | `packages/core/src/core/time-range.ts` |
102
+ | Export | Purpose | Source |
103
+ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
104
+ | `Time` | Point-in-time event key | `packages/core/src/core/time.ts` |
105
+ | `TimeRange` | Interval event key (start/end) | `packages/core/src/core/time-range.ts` |
106
+ | `Interval` | Labeled time-interval event key | `packages/core/src/core/interval.ts` |
107
+ | `TimeZone` | IANA zone as a calendar: `startOf` / `next` / `parts` / `instant` / `offsetAt` / `abbreviation`; interned, transition-cached; what `Sequence.calendar` buckets with | `packages/core/src/core/time-zone.ts` |
108
+ | `Event` | Immutable event: temporal key + typed payload | `packages/core/src/core/event.ts` |
109
+ | `toTimeRange` | Coerce temporal values to `TimeRange` | `packages/core/src/core/time-range.ts` |
109
110
 
110
111
  ### TimeSeries methods (all in `packages/core/src/batch/time-series.ts`)
111
112
 
@@ -158,14 +159,14 @@ Deliberately small — the ordering-based slice of the algebra, no calendar ops
158
159
 
159
160
  ### Key exported types (batch)
160
161
 
161
- | Type group | Names | Source |
162
- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
163
- | Schema contract | `SeriesSchema`, `RowForSchema`, `EventForSchema`, `EventDataForSchema`, `EventKeyForSchema`, `TimeSeriesInput`, `TimeSeriesJsonInput` | `packages/core/src/schema/index.ts` |
164
- | Aggregation specs | `AggregateReducer`, `AggregateMap`, `AggregateOutputMap`, `AggregateSchema`, `BinReducerName`, `BinOutput` | `packages/core/src/schema/index.ts`, `packages/core/src/column.ts` |
165
- | Operation schemas | `RollingSchema`, `RollingAlignment`, `AlignSchema`, `DiffSchema`, `SmoothSchema`, `SmoothMethod`, `FillStrategy`, `FillMapping` | `packages/core/src/schema/index.ts` |
166
- | Column/data kinds | `Column`, `KeyColumn`, `ColumnKind`, `ScalarKind`, `ScalarValue`, `ColumnValue`, `ArrayValue`, `ValidityBitmap` | `packages/core/src/columnar/` |
167
- | JSON wire format | `JsonRowFormat`, `JsonRowForSchema`, `JsonObjectRowForSchema`, `JsonValueForKind`, `JsonTimestampInput`, `JsonTimeRangeInput`, `JsonIntervalInput` | `packages/core/src/schema/index.ts` |
168
- | Temporal utility | `TemporalLike`, `DurationInput`, `CalendarUnit`, `TimeZoneOptions`, `KeyLike`, `BatchSampleStrategy`, `SequenceSample`, `SequenceCoverage` | `packages/core/src/core/`, `packages/core/src/sequence/` |
162
+ | Type group | Names | Source |
163
+ | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
164
+ | Schema contract | `SeriesSchema`, `RowForSchema`, `EventForSchema`, `EventDataForSchema`, `EventKeyForSchema`, `TimeSeriesInput`, `TimeSeriesJsonInput` | `packages/core/src/schema/index.ts` |
165
+ | Aggregation specs | `AggregateReducer`, `AggregateMap`, `AggregateOutputMap`, `AggregateSchema`, `BinReducerName`, `BinOutput` | `packages/core/src/schema/index.ts`, `packages/core/src/column.ts` |
166
+ | Operation schemas | `RollingSchema`, `RollingAlignment`, `AlignSchema`, `DiffSchema`, `SmoothSchema`, `SmoothMethod`, `FillStrategy`, `FillMapping` | `packages/core/src/schema/index.ts` |
167
+ | Column/data kinds | `Column`, `KeyColumn`, `ColumnKind`, `ScalarKind`, `ScalarValue`, `ColumnValue`, `ArrayValue`, `ValidityBitmap` | `packages/core/src/columnar/` |
168
+ | JSON wire format | `JsonRowFormat`, `JsonRowForSchema`, `JsonObjectRowForSchema`, `JsonValueForKind`, `JsonTimestampInput`, `JsonTimeRangeInput`, `JsonIntervalInput` | `packages/core/src/schema/index.ts` |
169
+ | Temporal utility | `TemporalLike`, `DurationInput`, `CalendarUnit`, `TimeZoneOptions`, `Disambiguation`, `ZonedParts`, `ZonedPartsInput`, `StartOfOptions`, `KeyLike`, `BatchSampleStrategy`, `SequenceSample`, `SequenceCoverage` | `packages/core/src/core/`, `packages/core/src/sequence/` |
169
170
 
170
171
  The `pond-ts/types` subpath re-exports the schema-as-contract types with zero
171
172
  runtime (`packages/core/src/schema/public.ts`).
@@ -250,17 +251,17 @@ Types: `UseSnapshotOptions`, `SnapshotSource` (structural — covers
250
251
 
251
252
  ### Components — layout & axes
252
253
 
253
- | Component | Key props | Purpose | Source |
254
- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
255
- | `ChartContainer` | `width`, `range?`, `theme?`, `cursor?`, `panZoom?`, `xScale?`, `bounds?`, `showAxis?`, `calendar?`, `origin?`, `maxBandWidth?`/`bandAlign?`, `onTrackerChanged?`, `onDrawStats?` | Root: shared x-scale, interactions, annotations | `packages/charts/src/ChartContainer.tsx` |
256
- | `ChartRow` | `height`, `cursor?` (deprecated — mount a cursor in the row) | One stacked plot band; owns its y-axes | `packages/charts/src/ChartRow.tsx` |
257
- | `Layers` | children | Mandatory z-stack inside a row (back-to-front) | `packages/charts/src/Layers.tsx` |
258
- | `YAxis` | `id` (req), `side?`, `scale?` (`'linear'` \| `'log'` \| `'symlog'`), `linearWindow?`, `min?`/`max?`, `format?`, `width?`, `hide?` | Y-axis gutter; layers bind via their `axis` prop | `packages/charts/src/YAxis.tsx` |
259
- | `XAxis` | `side?`, `label?`, `format?`, `ticks?`, `transform?`, `dateStyle?` | Placeable x-axis strip; kind inferred from data | `packages/charts/src/XAxis.tsx` |
260
- | `TimeAxis` / `CategoryAxis` | (XAxis props) | Thin `XAxis` presets | `packages/charts/src/TimeAxis.tsx`, `CategoryAxis.tsx` |
261
- | `Canvas` | `width`, `height`, `draw` | Low-level DPR-aware canvas primitive | `packages/charts/src/Canvas.tsx` |
262
- | `Selector` | `enabled?` (default `true`), `selected?` (mark \| set), `hovered?`, `onSelect?`, `onHover?`, `children?` | Wraps its scope; mounting enables click-select and owns the state it drives (RFC A10) | `packages/charts/src/selectors.tsx` |
263
- | `MultiSelector` | `enabled?`, `selected?`, `hovered?`, `sequence?`, `onSelect?`, `onHover?`, `children?` | Sweep-select superset of `Selector`: drag sweeps marks, release reports `(hits, modifiers, spans)` — plural, one per swept layer (RFC A5.2) | `packages/charts/src/selectors.tsx` |
254
+ | Component | Key props | Purpose | Source |
255
+ | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
256
+ | `ChartContainer` | `width`, `range?`, `theme?`, `cursor?`, `panZoom?`, `xScale?`, `bounds?`, `showAxis?`, `calendar?`, `timeZone?`, `origin?`, `maxBandWidth?`/`bandAlign?`, `onTrackerChanged?`, `onDrawStats?` | Root: shared x-scale, interactions, annotations; `timeZone` renders the time axis in an IANA zone (default: viewer-local; a `calendar.timeZone` supplies the default) | `packages/charts/src/ChartContainer.tsx` |
257
+ | `ChartRow` | `height`, `cursor?` (deprecated — mount a cursor in the row) | One stacked plot band; owns its y-axes | `packages/charts/src/ChartRow.tsx` |
258
+ | `Layers` | children | Mandatory z-stack inside a row (back-to-front) | `packages/charts/src/Layers.tsx` |
259
+ | `YAxis` | `id` (req), `side?`, `scale?` (`'linear'` \| `'log'` \| `'symlog'`), `linearWindow?`, `min?`/`max?`, `format?`, `width?`, `hide?` | Y-axis gutter; layers bind via their `axis` prop | `packages/charts/src/YAxis.tsx` |
260
+ | `XAxis` | `side?`, `label?`, `format?`, `ticks?`, `transform?`, `dateStyle?`, `timeZone?` (this strip in another IANA zone) | Placeable x-axis strip; kind inferred from data | `packages/charts/src/XAxis.tsx` |
261
+ | `TimeAxis` / `CategoryAxis` | (XAxis props) | Thin `XAxis` presets | `packages/charts/src/TimeAxis.tsx`, `CategoryAxis.tsx` |
262
+ | `Canvas` | `width`, `height`, `draw` | Low-level DPR-aware canvas primitive | `packages/charts/src/Canvas.tsx` |
263
+ | `Selector` | `enabled?` (default `true`), `selected?` (mark \| set), `hovered?`, `onSelect?`, `onHover?`, `children?` | Wraps its scope; mounting enables click-select and owns the state it drives (RFC A10) | `packages/charts/src/selectors.tsx` |
264
+ | `MultiSelector` | `enabled?`, `selected?`, `hovered?`, `sequence?`, `onSelect?`, `onHover?`, `children?` | Sweep-select superset of `Selector`: drag sweeps marks, release reports `(hits, modifiers, spans)` — plural, one per swept layer (RFC A5.2) | `packages/charts/src/selectors.tsx` |
264
265
 
265
266
  ### Components — draw layers
266
267
 
@@ -386,44 +387,47 @@ Series shapes (same file): `ChartSeries`, `BandSeries`, `BoxSeries`,
386
387
 
387
388
  ### Live values, scales & key types
388
389
 
389
- | Export | Purpose | Source |
390
- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ----------------------------------------- |
391
- | `createLiveValue` / `LiveValue` | Imperative push channel for high-frequency indicator updates (isolated repaint) | `packages/charts/src/indicators.tsx` |
392
- | `scaleTradingTime` / `TradingTimeScale` | Discontinuous time scale collapsing closed-market gaps | `packages/charts/src/tradingTimeScale.ts` |
393
- | `DiscontinuityProvider` | Gap topology consumed by the trading-time scale | `packages/charts/src/tradingTimeScale.ts` |
394
- | `scaleBand` / `ScaleBand` | Ordinal slot scale for the category axis | `packages/charts/src/bandScale.ts` |
395
- | `GapMode` | `'none' \| 'empty' \| 'dashed' \| 'step' \| 'fade'` (Line/Area `gaps` prop) | `packages/charts/src/gaps.ts` |
396
- | `DecimateOption` | `<LineChart decimate>` M4 viewport decimation (`bool \| { threshold }`) | `packages/charts/src/decimate.ts` |
397
- | `CursorMode` | `'none' \| 'line' \| 'point' \| 'inline' \| 'flag' \| 'crosshair' \| 'region'` | `packages/charts/src/context.ts` |
398
- | `TrackerInfo` / `TrackerSample` | Hover readout payload (`onTrackerChanged`) | `packages/charts/src/context.ts` |
399
- | `AnnotationKind` / `CreateSpec` | Annotation identity + draw-gesture payload (`onCreate`) | `packages/charts/src/context.ts` |
400
- | `SelectInfo` | Selection/hover payload (`Selector`/`MultiSelector` `onSelect`/`onHover`) | `packages/charts/src/context.ts` |
401
- | `SelectModifiers` | Keyboard modifiers on a click, 2nd arg to `onSelect` | `packages/charts/src/context.ts` |
402
- | `SelectorProps` | `<Selector>`'s props — `enabled?` / `selected?` / `hovered?` / `onSelect?` / `onHover?` / `children?` | `packages/charts/src/selectors.tsx` |
403
- | `MultiSelectorProps` | `<MultiSelector>`'s props the above plus `sequence?`, with plural callbacks | `packages/charts/src/selectors.tsx` |
404
- | `RangeSpan` | `<RangeCursor onDragRelease>` payload `{ x: [lo, hi], y? }` in axis units | `packages/charts/src/context.ts` |
405
- | `SpanSelection` | Range entry for `selected` one layer's marks over `x`/`y`/`rows` (RFC A5.2) | `packages/charts/src/context.ts` |
406
- | `SelectionEntry` | One `selected` array entry: `SelectInfo \| SpanSelection` | `packages/charts/src/context.ts` |
407
- | `selectionContains` | Is a hit in a mixed selection? The same membership predicate the layers run | `packages/charts/src/span.ts` |
408
- | `sameMark` | Are two hits the same mark? Full identity (`id`, `mark`-or-`key`, `label`) | `packages/charts/src/span.ts` |
409
- | `isSpanSelection` | Entry discriminant narrows a `SelectionEntry` to `SpanSelection` | `packages/charts/src/span.ts` |
410
- | `DrawStatsFrame` / `LayerDrawInfo` | Per-repaint draw-cost + decimation stats (`ChartContainer` `onDrawStats`) | `packages/charts/src/context.ts` |
411
- | `TimeGrain` | Coarse time unit for grain-aware formatting | `packages/charts/src/tickLadder.ts` |
412
- | `SwatchSpec` / `LegendItemInput` | Legend swatch vocabulary + explicit-rows input (`<Legend items>`) | `packages/charts/src/swatch.ts` |
413
- | `useChartLegend` | Headless legend hook: rows (items grouped by chart row) + `hover`/`select` verbs | `packages/charts/src/useChartLegend.ts` |
414
- | `ChartLegend` / `LegendRow` / `LegendItem` | The hook's return shape (`rows` group `items`; items carry `selected`/`hovered`) | `packages/charts/src/useChartLegend.ts` |
415
- | `useChartFrame` | Resolved plot geometry: plot rect, gutters, x scale, a row's y scales, band slot edges | `packages/charts/src/useChartFrame.ts` |
416
- | `ChartFrame` / `ChartFrameRow` | The hook's return shape container x half, plus a row y half that is `null` outside a `<ChartRow>` | `packages/charts/src/useChartFrame.ts` |
417
- | `ChartBands` / `ChartBand` | Ordinal slot geometry on a category axis (`count`/`pitch`/`labels`/`at(i)`); `null` on time/value | `packages/charts/src/useChartFrame.ts` |
418
- | `ChartXScale` | The union the container's shared x scale resolves to (time / linear / trading / band / elapsed) | `packages/charts/src/context.ts` |
419
- | `LegendPlacement` | `'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right'` | `packages/charts/src/Legend.tsx` |
420
- | `Curve` | Path interpolation: `'linear' \| 'monotone' \| 'natural' \| 'basis' \| 'step'` | `packages/charts/src/curve.ts` |
421
- | `RadiusEncoding` / `ColorEncoding` | Data-driven scatter size/colour | `packages/charts/src/encoding.ts` |
422
- | `CandleVariant` / `ColorBy` | OHLC mark shape / colouring strategy | `packages/charts/src/ohlc.ts` |
423
- | `AxisFormat` / `CursorFormat` | Tick and cursor-readout formatting (d3 specifier or fn) | `packages/charts/src/format.ts` |
424
- | `AxisTransform` | Monotonic `to`/`from` pair for derived-unit x-axis relabeling | `packages/charts/src/derivedTicks.ts` |
425
- | `AxisMouseEvent` / `AxisMouseHandler` | Axis `onMouseEvent` payload — the mouse event, the axis's `id`, and the value/label under the pointer | `packages/charts/src/axis-events.ts` |
426
- | `Orientation` | Bar growth direction | `packages/charts/src/bars.ts` |
390
+ | Export | Purpose | Source |
391
+ | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------- |
392
+ | `createLiveValue` / `LiveValue` | Imperative push channel for high-frequency indicator updates (isolated repaint) | `packages/charts/src/indicators.tsx` |
393
+ | `scaleTradingTime` / `TradingTimeScale` | Discontinuous time scale collapsing closed-market gaps; `scaleTradingTime(provider, { timeZone })` runs its tick ladder and labels in an IANA zone; `.withTimeZone(zone)` / `.timeZone()` re-derive the same mapping in another zone | `packages/charts/src/tradingTimeScale.ts` |
394
+ | `DiscontinuityProvider` | Gap topology consumed by the trading-time scale; optional `withTimeZone(zone)` for providers whose day anchors move with the zone | `packages/charts/src/tradingTimeScale.ts` |
395
+ | `identityProvider` | The gap-free provider a plain continuous time axis runs on; `identityProvider({ timeZone })` puts its day anchors on that zone's midnights | `packages/charts/src/tradingTimeScale.ts` |
396
+ | `TradingCalendarLike` | Structural shape of a trading calendar `ChartContainer calendar` accepts: `discontinuities({ spacing })` + optional `timeZone` (the axis default) | `packages/charts/src/tradingTimeScale.ts` |
397
+ | `ScaleTimeZoneOptions` | `{ timeZone? }` for `scaleTradingTime` / `identityProvider` | `packages/charts/src/tradingTimeScale.ts` |
398
+ | `scaleBand` / `ScaleBand` | Ordinal slot scale for the category axis | `packages/charts/src/bandScale.ts` |
399
+ | `GapMode` | `'none' \| 'empty' \| 'dashed' \| 'step' \| 'fade'` (Line/Area `gaps` prop) | `packages/charts/src/gaps.ts` |
400
+ | `DecimateOption` | `<LineChart decimate>` M4 viewport decimation (`bool \| { threshold }`) | `packages/charts/src/decimate.ts` |
401
+ | `CursorMode` | `'none' \| 'line' \| 'point' \| 'inline' \| 'flag' \| 'crosshair' \| 'region'` | `packages/charts/src/context.ts` |
402
+ | `TrackerInfo` / `TrackerSample` | Hover readout payload (`onTrackerChanged`) | `packages/charts/src/context.ts` |
403
+ | `AnnotationKind` / `CreateSpec` | Annotation identity + draw-gesture payload (`onCreate`) | `packages/charts/src/context.ts` |
404
+ | `SelectInfo` | Selection/hover payload (`Selector`/`MultiSelector` `onSelect`/`onHover`) | `packages/charts/src/context.ts` |
405
+ | `SelectModifiers` | Keyboard modifiers on a click, 2nd arg to `onSelect` | `packages/charts/src/context.ts` |
406
+ | `SelectorProps` | `<Selector>`'s props `enabled?` / `selected?` / `hovered?` / `onSelect?` / `onHover?` / `children?` | `packages/charts/src/selectors.tsx` |
407
+ | `MultiSelectorProps` | `<MultiSelector>`'s props the above plus `sequence?`, with plural callbacks | `packages/charts/src/selectors.tsx` |
408
+ | `RangeSpan` | `<RangeCursor onDragRelease>` payload `{ x: [lo, hi], y? }` in axis units | `packages/charts/src/context.ts` |
409
+ | `SpanSelection` | Range entry for `selected` one layer's marks over `x`/`y`/`rows` (RFC A5.2) | `packages/charts/src/context.ts` |
410
+ | `SelectionEntry` | One `selected` array entry: `SelectInfo \| SpanSelection` | `packages/charts/src/context.ts` |
411
+ | `selectionContains` | Is a hit in a mixed selection? The same membership predicate the layers run | `packages/charts/src/span.ts` |
412
+ | `sameMark` | Are two hits the same mark? Full identity (`id`, `mark`-or-`key`, `label`) | `packages/charts/src/span.ts` |
413
+ | `isSpanSelection` | Entry discriminant narrows a `SelectionEntry` to `SpanSelection` | `packages/charts/src/span.ts` |
414
+ | `DrawStatsFrame` / `LayerDrawInfo` | Per-repaint draw-cost + decimation stats (`ChartContainer` `onDrawStats`) | `packages/charts/src/context.ts` |
415
+ | `TimeGrain` | Coarse time unit for grain-aware formatting | `packages/charts/src/tickLadder.ts` |
416
+ | `SwatchSpec` / `LegendItemInput` | Legend swatch vocabulary + explicit-rows input (`<Legend items>`) | `packages/charts/src/swatch.ts` |
417
+ | `useChartLegend` | Headless legend hook: rows (items grouped by chart row) + `hover`/`select` verbs | `packages/charts/src/useChartLegend.ts` |
418
+ | `ChartLegend` / `LegendRow` / `LegendItem` | The hook's return shape (`rows` group `items`; items carry `selected`/`hovered`) | `packages/charts/src/useChartLegend.ts` |
419
+ | `useChartFrame` | Resolved plot geometry: plot rect, gutters, x scale, a row's y scales, band slot edges | `packages/charts/src/useChartFrame.ts` |
420
+ | `ChartFrame` / `ChartFrameRow` | The hook's return shape container x half, plus a row y half that is `null` outside a `<ChartRow>` | `packages/charts/src/useChartFrame.ts` |
421
+ | `ChartBands` / `ChartBand` | Ordinal slot geometry on a category axis (`count`/`pitch`/`labels`/`at(i)`); `null` on time/value | `packages/charts/src/useChartFrame.ts` |
422
+ | `ChartXScale` | The union the container's shared x scale resolves to (time / linear / trading / band / elapsed) | `packages/charts/src/context.ts` |
423
+ | `LegendPlacement` | `'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right'` | `packages/charts/src/Legend.tsx` |
424
+ | `Curve` | Path interpolation: `'linear' \| 'monotone' \| 'natural' \| 'basis' \| 'step'` | `packages/charts/src/curve.ts` |
425
+ | `RadiusEncoding` / `ColorEncoding` | Data-driven scatter size/colour | `packages/charts/src/encoding.ts` |
426
+ | `CandleVariant` / `ColorBy` | OHLC mark shape / colouring strategy | `packages/charts/src/ohlc.ts` |
427
+ | `AxisFormat` / `CursorFormat` | Tick and cursor-readout formatting (d3 specifier or fn) | `packages/charts/src/format.ts` |
428
+ | `AxisTransform` | Monotonic `to`/`from` pair for derived-unit x-axis relabeling | `packages/charts/src/derivedTicks.ts` |
429
+ | `AxisMouseEvent` / `AxisMouseHandler` | Axis `onMouseEvent` payload — the mouse event, the axis's `id`, and the value/label under the pointer | `packages/charts/src/axis-events.ts` |
430
+ | `Orientation` | Bar growth direction | `packages/charts/src/bars.ts` |
427
431
 
428
432
  ---
429
433
 
@@ -618,16 +622,16 @@ erased types. A separate subpath: importing it pulls in every study.
618
622
 
619
623
  ### Trading calendars & sessions
620
624
 
621
- | Export | Purpose | Source |
622
- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------- |
623
- | `TradingCalendar` | Query API: `.sessions()`, `.sessionOn()`, `.isTradingDay()`, `.isOpen()`, `.sessionsInRange()`, `.sessionSequence()`, `.barSequence(period)`, `.tagSessions()`, `.discontinuities()` | `packages/financial/src/calendar/` |
624
- | `generateSessions` | `Session[]` from `SessionRules` over a date range (DST-correct) | `packages/financial/src/calendar/` |
625
- | `normalizeSessions` | Validate + sort an explicit session list | `packages/financial/src/calendar/` |
626
- | `identityDiscontinuity` / `segmentDiscontinuity` / `weekendSkip` | `DiscontinuityProvider`s for the trading-time axis | `packages/financial/src/calendar/` |
627
- | Types | `Session`, `SessionBreak`, `SessionRules`, `DateRange`, `InstantRange`, `TaggedSchema`, `LiveSegment`, `DiscontinuityProvider` | `packages/financial/src/calendar/` |
628
- | `SessionSource` / `SessionAnchorOptions` | The session-anchored studies' input: `TradingCalendar \| Session[]` (`sessions`), or a session-id column name (`session`), plus `stamped` | `packages/financial/src/contract/session-anchor.ts` |
629
- | `PIVOT_METHODS` / `PivotMethod` | The four pivot formula sets (`standard`, `fibonacci`, `woodie`, `camarilla`) | `packages/financial/src/kernels/pivot.ts` |
630
- | `PivotPointsSchema` / `CamarillaPivotPointsSchema` / `PivotPointsResult` | `pivotPoints`' method-dependent appended-schema types (7 columns, or 9 for Camarilla) | `packages/financial/src/studies/pivot-points.ts` |
625
+ | Export | Purpose | Source |
626
+ | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
627
+ | `TradingCalendar` | `timeZone` (the exchange zone: `fromRules`' `rules.timeZone`, or `fromSessions(list, { timeZone })`) + query API: `.sessions()`, `.sessionOn()`, `.isTradingDay()`, `.isOpen()`, `.sessionsInRange()`, `.sessionSequence()`, `.barSequence(period)`, `.tagSessions()`, `.discontinuities()` | `packages/financial/src/calendar/` |
628
+ | `generateSessions` | `Session[]` from `SessionRules` over a date range (DST-correct) | `packages/financial/src/calendar/` |
629
+ | `normalizeSessions` | Validate + sort an explicit session list | `packages/financial/src/calendar/` |
630
+ | `identityDiscontinuity` / `segmentDiscontinuity` / `weekendSkip` | `DiscontinuityProvider`s for the trading-time axis | `packages/financial/src/calendar/` |
631
+ | Types | `Session`, `SessionBreak`, `SessionRules`, `DateRange`, `InstantRange`, `TaggedSchema`, `LiveSegment`, `DiscontinuityProvider` | `packages/financial/src/calendar/` |
632
+ | `SessionSource` / `SessionAnchorOptions` | The session-anchored studies' input: `TradingCalendar \| Session[]` (`sessions`), or a session-id column name (`session`), plus `stamped` | `packages/financial/src/contract/session-anchor.ts` |
633
+ | `PIVOT_METHODS` / `PivotMethod` | The four pivot formula sets (`standard`, `fibonacci`, `woodie`, `camarilla`) | `packages/financial/src/kernels/pivot.ts` |
634
+ | `PivotPointsSchema` / `CamarillaPivotPointsSchema` / `PivotPointsResult` | `pivotPoints`' method-dependent appended-schema types (7 columns, or 9 for Camarilla) | `packages/financial/src/studies/pivot-points.ts` |
631
635
 
632
636
  ### Contract & constants
633
637
 
@@ -712,31 +716,31 @@ Typed dataflow graphs for pipelines whose **shape is data** (runtime-assembled,
712
716
  user-edited, one computation fanned out to several consumers). Chaining stays
713
717
  the default for pipelines known at authoring time — see the package README.
714
718
 
715
- | Group | Exports | Source |
716
- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
717
- | Worker pool (Node) | `HostPool` (`start`, `run`, `close`, `size`, `inFlight`); types `HostPoolOptions`, `PoolSetup`, `PoolSetupConfig`; `toWire` / `fromWire`, types `WireResult`, `WireColumn` — subpath `@pond-ts/process/pool` | `packages/process/src/pool/index.ts` |
718
- | Ports | `Inlet`, `Outlet` (typed fields on `node.in` / `node.out`; `get()`, `peek()`, `version`, `connect`, `disconnect`) | `packages/process/src/port.ts` |
719
- | Nodes | `Node` (`in`, `out`, `dirty`, `error`, `invalidate()`), `defineNode` (reusable multi-output node type), `derive` (single-output, wired inline) | `packages/process/src/node.ts` |
720
- | Port declaration | `port<T>({ equals, defaultValue })`; types `PortSpec`, `PortSpecMap`, `PortValue`, `PortValues` | `packages/process/src/types.ts` |
721
- | Sources | `source<T>()` → `SourceNode` (`set()`), `fromLive(liveSource)` → `LiveSourceNode` (`dispose()`); `GraphSource` (bind contract — looser than core's `LiveSource`, accepts `LiveAggregation`), `SnapshotSource`, `NoInputs` | `packages/process/src/source.ts` |
722
- | Graph view | `Graph` (`Graph.from(...roots)`, `nodes`, `order()`, `edges()`, `toJSON()`); types `GraphEdge`, `GraphJson`, `GraphNodeJson`, `GraphEdgeJson` | `packages/process/src/graph.ts` |
723
- | Range output buffers | `prepareRange(length, keep, prior)` → `RangeOutput` (`values`, `bits`, `set`, `clear`) carrying `[0, keep)` forward as blocks — values **and** validity; `sealRange(out, length)` → `Float64Column`; `validityByteCount`. Reached from an op as `ctx.out[n]` | `packages/process/src/column.ts` |
724
- | Ranged recompute | `graph.setSourceFrom(series, changedFrom)` — declares which row first changed; `graph.recomputes` → `{ ranged, full }`. An op opts in with `OpDef.runRange(ctx)`, receiving `{ from, to, previous, previousView, out }` (type `RangeContext`) — write into `out` and return nothing for the block path alongside the usual context. Requires `lookback`. Falls back to a full `run` whenever anything is missing | `packages/process/src/plan/graph.ts` |
725
- | Node budget | `bind(series, { registry, budgetBytes })` — engine-wide cap on retained node values, LRU, enforced after each `run`; `graph.retainedBytes` / `graph.evictions` / `graph.enforceBudget()`. Unbounded when omitted. Skips a node whose consumer still holds its outlet | `packages/process/src/plan/graph.ts` |
726
- | Plan history | `requiredHistory(registry, plan)` → `{ known, rows?, undeclared, byOp }` — the minimum safe tail in rows, folded from per-op `OpDef.lookback`. Sums along nesting, maxes across siblings. `known: false` names ops with no declared lookback rather than defaulting to zero (type `HistoryResult`) | `packages/process/src/plan/history.ts` |
727
- | Column values | `packColumn` (values → packed `Float64Column`, NaN = missing), `columnBytes` (retained size, for a byte budget), `appendColumn` (column → series; boxing-free when gapless), `columnBuffers` / `columnFromBuffers` (the buffer pair a column is, for an isolate boundary; type `ColumnBuffers`), `columnView` (zero-copy borrowed read view for in-process folds; type `ColumnView`) | `packages/process/src/column.ts` |
728
- | Plan — registry | `createRegistry({ folds })` / `Registry` (`define`, `get`, `foldFor`, `outputsOf`, `resolveParams` (`{ validate: false }` applies defaults and skips every check), `byFamily`, `describe`, `toJsonSchema`), param builders `int` / `num` / `choice` / `flag`, `UnknownOpError`, `ParamError` | `packages/process/src/plan/registry.ts`, `params.ts` |
729
- | Plan — identity | `specId(registry, spec, { validate })` (content-addressed, param-order invariant, defaults materialized; `validate: false` is **total** — names a spec that would not compile in a separate `p1?:` namespace that cannot collide with a valid id; a valid spec's id is identical either way), `SpecIdOptions`, `refToId`, `explain`, `unitOf`, `columnsOf`, `dependsOn`, `outputKey` | `packages/process/src/plan/identity.ts` |
730
- | Plan — types | `Spec`, `Plan`, `Input` (column name \| `Spec` \| `PickedOutput`), `SpecRef`, `Def` (`OpDef` \| `FoldDef`), `OpContext`, `OpResult`, `FoldContext`, `FactBody`, `isFold`, `ParamDef`, `Params`, `Units`, `InputDef`, `OutputDef` | `packages/process/src/plan/types.ts` |
731
- | Plan — bind / run | `bind(series, { registry, units })` → `BoundGraph` (`compile`, `setSource`, `ids`, `series`, `columnOf`), `run(graph, { plan, select, onError })` → `RunResult`, `UnitError`, `UnknownColumnError` (a raw string input naming no column of the bound series, checked over the whole closure and re-checked on the warm path) | `packages/process/src/plan/graph.ts`, `run.ts` |
732
- | Plan — request/response | `RunRequest` (`PlanRequest` \| `SlotRequest`), `RunOptions`, `RunResult`, `Select` (`{ on, output?, name? }` — points at a node; what comes back is what that node produces), `ErrorPolicy`, `Fact` (carries `op`), `OutputInfo`, `Skipped` (`spec`, `select`, `reason`, `code` — the failure's kind, matching the error class a throw would have carried), `NodeTiming` (`slot`, `pulled`, `cached`, `ms`, `inputs`) | `packages/process/src/plan/run.ts` |
733
- | Plan — host | `createHost({ registry, units, sources })` → `Host` (`add`, `has`, `datasets`, `graphFor`, `run`, `runAsync`), `toWire`, `UnknownDatasetError`; local-string `Envelope` (`PlanEnvelope` \| `SlotEnvelope`), remote-capable `AsyncEnvelope` (`AsyncPlanEnvelope` \| `AsyncSlotEnvelope` \| `Envelope`), `DatasetInfo`, `WireResult` | `packages/process/src/plan/host.ts` |
734
- | Plan — slots | `expandSlots(slots, columns)` → `Map<slot, Spec>` (expands to the nested form, so ids match by construction; `slot#Output` picks one output), `SlotError`; types `SlotDef` (`{ op, params, in }`), `Slots` | `packages/process/src/plan/slots.ts` |
735
- | Plan — builder | `plan(from)` → low-level `PlanBuilder`; `process(registry, from)` → typed fluent `ProcessBuilder` (`column`, op methods, `outputs`), `BuilderError`; types `NodeHandle`, `OutputHandle`, `FluentColumnRef`, `SingleColumnNode`, `MultiColumnNode`, `ColumnSelection`, `FactRef`, `BuiltRequest` | `packages/process/src/plan/builder.ts`, `fluent.ts` |
736
- | Plan — async sources | `defineSource({ name, load })`, `createSourceRegistry()` / `SourceRegistry`, `sourceId`, `UnknownSourceError`; types `SourceRef`, `SourceParams`, `LoadedSource` (value + revision), `SourceLoadContext`, `SourceDef` | `packages/process/src/plan/source.ts` |
737
- | Plan — folds | `STANDARD_FOLDS` and the four it holds — `last`, `extremes`, `percentileRank`, `shape` — pre-registered by `createRegistry()`; each a plain `FoldDef`, so a consumer can `define` over one | `packages/process/src/plan/folds.ts` |
738
- | Errors | `ProcessError` (base; `code` — a stable per-class literal, minification-proof, also surfaced on `Skipped`), `CycleError`, `UnconnectedInputError`, `MissingOutputError`, `UnsetSourceError` | `packages/process/src/errors.ts` |
739
- | Node type helpers | `NodeSpec`, `NodeFactory`, `InletsFor`, `OutletsFor`, `OutletValue`, `SpecsForOutlets`, `DerivedOutput` | `packages/process/src/node.ts` |
719
+ | Group | Exports | Source |
720
+ | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
721
+ | Worker pool (Node) | `HostPool` (`start`, `run`, `close`, `size`, `inFlight`); types `HostPoolOptions`, `PoolSetup`, `PoolSetupConfig`; `toWire` / `fromWire`, types `WireResult`, `WireColumn` — subpath `@pond-ts/process/pool` | `packages/process/src/pool/index.ts` |
722
+ | Ports | `Inlet`, `Outlet` (typed fields on `node.in` / `node.out`; `get()`, `peek()`, `version`, `connect`, `disconnect`) | `packages/process/src/port.ts` |
723
+ | Nodes | `Node` (`in`, `out`, `dirty`, `error`, `invalidate()`), `defineNode` (reusable multi-output node type), `derive` (single-output, wired inline) | `packages/process/src/node.ts` |
724
+ | Port declaration | `port<T>({ equals, defaultValue })`; types `PortSpec`, `PortSpecMap`, `PortValue`, `PortValues` | `packages/process/src/types.ts` |
725
+ | Sources | `source<T>()` → `SourceNode` (`set()`), `fromLive(liveSource)` → `LiveSourceNode` (`dispose()`); `GraphSource` (bind contract — looser than core's `LiveSource`, accepts `LiveAggregation`), `SnapshotSource`, `NoInputs` | `packages/process/src/source.ts` |
726
+ | Graph view | `Graph` (`Graph.from(...roots)`, `nodes`, `order()`, `edges()`, `toJSON()`); types `GraphEdge`, `GraphJson`, `GraphNodeJson`, `GraphEdgeJson` | `packages/process/src/graph.ts` |
727
+ | Range output buffers | `prepareRange(length, keep, prior)` → `RangeOutput` (`values`, `bits`, `set`, `clear`) carrying `[0, keep)` forward as blocks — values **and** validity; `sealRange(out, length)` → `Float64Column`; `validityByteCount`. Reached from an op as `ctx.out[n]` | `packages/process/src/column.ts` |
728
+ | Ranged recompute | `graph.setSourceFrom(series, changedFrom)` — declares which row first changed; `graph.recomputes` → `{ ranged, full }`. An op opts in with `OpDef.runRange(ctx)`, receiving `{ from, to, previous, previousView, out }` (type `RangeContext`) — write into `out` and return nothing for the block path alongside the usual context. Requires `lookback`. Falls back to a full `run` whenever anything is missing | `packages/process/src/plan/graph.ts` |
729
+ | Node budget | `bind(series, { registry, budgetBytes })` — engine-wide cap on retained node values, LRU, enforced after each `run`; `graph.retainedBytes` / `graph.evictions` / `graph.enforceBudget()`. Unbounded when omitted. Skips a node whose consumer still holds its outlet | `packages/process/src/plan/graph.ts` |
730
+ | Plan history | `requiredHistory(registry, plan)` → `{ known, rows?, undeclared, byOp }` — the minimum safe tail in rows, folded from per-op `OpDef.lookback`. Sums along nesting, maxes across siblings. `known: false` names ops with no declared lookback rather than defaulting to zero (type `HistoryResult`) | `packages/process/src/plan/history.ts` |
731
+ | Column values | `packColumn` (values → packed `Float64Column`, NaN = missing), `columnBytes` (retained size, for a byte budget), `appendColumn` (column → series; boxing-free when gapless), `columnBuffers` / `columnFromBuffers` (the buffer pair a column is, for an isolate boundary; type `ColumnBuffers`), `columnView` (zero-copy borrowed read view for in-process folds; type `ColumnView`) | `packages/process/src/column.ts` |
732
+ | Plan — registry | `createRegistry({ folds })` / `Registry` (`define`, `get`, `foldFor`, `outputsOf`, `resolveParams` (`{ validate: false }` applies defaults and skips every check), `byFamily`, `describe`, `toJsonSchema`, `checkArity`), param builders `int` / `num` / `choice` / `flag`, `UnknownOpError`, `ParamError`, `ArityError` | `packages/process/src/plan/registry.ts`, `params.ts` |
733
+ | Plan — identity | `specId(registry, spec, { validate })` (content-addressed, param-order invariant, defaults materialized; `validate: false` is **total over arbitrary JSON** — names a spec that would not compile, including malformed shapes, in a separate `p1?:` namespace that cannot collide with a valid id; a valid spec's id is identical either way. Judges op existence, params **and arity**), `SpecIdOptions`, `refToId`, `explain`, `unitOf`, `columnsOf`, `dependsOn`, `outputKey` | `packages/process/src/plan/identity.ts` |
734
+ | Plan — types | `Spec`, `Plan`, `Input` (column name \| `Spec` \| `PickedOutput`), `SpecRef`, `Def` (`OpDef` \| `FoldDef`), `OpContext`, `OpResult`, `FoldContext`, `FactBody`, `isFold`, `ParamDef`, `Params`, `Units`, `InputDef`, `OutputDef` | `packages/process/src/plan/types.ts` |
735
+ | Plan — bind / run | `bind(series, { registry, units })` → `BoundGraph` (`compile`, `setSource`, `ids`, `series`, `columnOf`), `run(graph, { plan, select, onError })` → `RunResult`, `UnitError`, `UnknownColumnError` (a raw string input naming no column of the bound series, checked over the whole closure and re-checked on the warm path) | `packages/process/src/plan/graph.ts`, `run.ts` |
736
+ | Plan — request/response | `RunRequest` (`PlanRequest` \| `SlotRequest`), `RunOptions`, `RunResult`, `Select` (`{ on, output?, name? }` — points at a node; what comes back is what that node produces), `ErrorPolicy`, `Fact` (carries `op`), `OutputInfo`, `Skipped` (`spec` — echoed verbatim, `params`/`inputs` typed `unknown`; `select`, `reason`, `code` — the failure's kind, matching the error class a throw would have carried), `NodeTiming` (`slot`, `pulled`, `cached`, `ms`, `inputs`) | `packages/process/src/plan/run.ts` |
737
+ | Plan — host | `createHost({ registry, units, sources })` → `Host` (`add`, `has`, `datasets`, `graphFor`, `run`, `runAsync`), `toWire`, `UnknownDatasetError`; local-string `Envelope` (`PlanEnvelope` \| `SlotEnvelope`), remote-capable `AsyncEnvelope` (`AsyncPlanEnvelope` \| `AsyncSlotEnvelope` \| `Envelope`), `DatasetInfo`, `WireResult` | `packages/process/src/plan/host.ts` |
738
+ | Plan — slots | `expandSlots(slots, columns)` → `Map<slot, Spec>` (expands to the nested form, so ids match by construction; `slot#Output` picks one output), `SlotError`; types `SlotDef` (`{ op, params, in }`), `Slots` | `packages/process/src/plan/slots.ts` |
739
+ | Plan — builder | `plan(from)` → low-level `PlanBuilder`; `process(registry, from)` → typed fluent `ProcessBuilder` (`column`, op methods, `outputs`), `BuilderError`; types `NodeHandle`, `OutputHandle`, `FluentColumnRef`, `SingleColumnNode`, `MultiColumnNode`, `ColumnSelection`, `FactRef`, `BuiltRequest` | `packages/process/src/plan/builder.ts`, `fluent.ts` |
740
+ | Plan — async sources | `defineSource({ name, load })`, `createSourceRegistry()` / `SourceRegistry`, `sourceId`, `UnknownSourceError`; types `SourceRef`, `SourceParams`, `LoadedSource` (value + revision), `SourceLoadContext`, `SourceDef` | `packages/process/src/plan/source.ts` |
741
+ | Plan — folds | `STANDARD_FOLDS` and the four it holds — `last`, `extremes`, `percentileRank`, `shape` — pre-registered by `createRegistry()`; each a plain `FoldDef`, so a consumer can `define` over one | `packages/process/src/plan/folds.ts` |
742
+ | Errors | `ProcessError` (base; `code` — a stable per-class literal, minification-proof, also surfaced on `Skipped`), `CycleError`, `UnconnectedInputError`, `MissingOutputError`, `UnsetSourceError` | `packages/process/src/errors.ts` |
743
+ | Node type helpers | `NodeSpec`, `NodeFactory`, `InletsFor`, `OutletsFor`, `OutletValue`, `SpecsForOutlets`, `DerivedOutput` | `packages/process/src/node.ts` |
740
744
 
741
745
  Note: this package's `npm test` includes a `test:dts` step that typechecks the
742
746
  **emitted** `dist/*.d.ts` from a consumer's perspective (`test-dts/`,
package/CHANGELOG.md CHANGED
@@ -8,7 +8,9 @@ The `@pond-ts` packages — `pond-ts`, `@pond-ts/react`, `@pond-ts/charts`,
8
8
  under a single `v*` tag, so this file covers them all. Pre-1.0: minor bumps may
9
9
  include new features and type-level changes; patch bumps are strictly additive.
10
10
 
11
- [Unreleased]: https://github.com/pond-ts/pond/compare/v0.68.0...HEAD
11
+ [Unreleased]: https://github.com/pond-ts/pond/compare/v0.70.0...HEAD
12
+ [0.70.0]: https://github.com/pond-ts/pond/compare/v0.69.0...v0.70.0
13
+ [0.69.0]: https://github.com/pond-ts/pond/compare/v0.68.0...v0.69.0
12
14
  [0.68.0]: https://github.com/pond-ts/pond/compare/v0.67.0...v0.68.0
13
15
  [0.67.0]: https://github.com/pond-ts/pond/compare/v0.66.0...v0.67.0
14
16
  [0.66.0]: https://github.com/pond-ts/pond/compare/v0.65.0...v0.66.0
@@ -71,6 +73,150 @@ include new features and type-level changes; patch bumps are strictly additive.
71
73
 
72
74
  ## [Unreleased]
73
75
 
76
+ ## [0.70.0] — 2026-09-18
77
+
78
+ ### Added
79
+
80
+ - `@pond-ts/charts`: **`<BandChart sessionBreaks>`** — the same trading-axis
81
+ session break `<LineChart>` has had since v0.45.0. On a discontinuous
82
+ (`discontinuities` / `calendar`) axis the fill previously ran a near-vertical
83
+ sliver from one session's last sample to the next session's first, because
84
+ the collapsed overnight gap put them a pixel apart; `sessionBreaks` ends the
85
+ envelope at the close and re-starts it at the open, so a band and its centre
86
+ line break in step. A **scale** break, orthogonal to the NaN **data** gaps a
87
+ band always breaks at; default `false` (unchanged output). Decimation
88
+ composes: `decimateBand` folds each break instant into the pixel-column
89
+ edges and bakes a `NaN` sample at it, so no column merges two sessions'
90
+ envelopes. Stories `Axes/TradingTimeAxis / SessionBreaksBand` and
91
+ `Performance/Decimation / TradingSessionBreaksBand`.
92
+ - `@pond-ts/process`: **`ArityError`**, and **arity is now part of what `specId`
93
+ can judge**. A spec whose `inputs` count does not match the op's — including
94
+ one carrying no `inputs` at all — was named `p1:sma(;period=20)`, a _valid_
95
+ id for something that cannot compile, and then died at `compile` as a bare
96
+ `TypeError` reading `.length` of `undefined`, reaching the consumer as a
97
+ `Skipped` with **no `code`** (which under that contract means "op code
98
+ threw"). Arity is decidable from the registry alone, so strict `specId` now
99
+ raises `ArityError` and lenient mode marks the id `p1?:`.
100
+ `Registry.checkArity(op, inputs)` is the shared check `compile` uses too.
101
+
102
+ ### Changed
103
+
104
+ - `@pond-ts/financial`: **`StudyOutput.id` documents the `@pond-ts/process`
105
+ bridge**, and a new `test/catalog-process.test.ts` pins it. The field is a
106
+ *financial column suffix*; process's `OutputDef.id` is a *process outlet
107
+ id*; they share a name and are different namespaces. Process names its own
108
+ columns (`specId + OutputDef.id`) and matches an op's return to its outputs
109
+ positionally, so a study's own column names never reach it — which means a
110
+ registry bridging the two chooses its own suffixes, and for the **twelve**
111
+ multi-output studies that claim the bare prefix (`trix`, `superTrend`,
112
+ `klinger`, …) it must: process rejects `''` on a multi-output op, because
113
+ there the column would be named exactly the spec id, itself a legal column
114
+ reference. The map is `outputs.length > 1 && id === ''` → `'value'` — not
115
+ `id === ''`, which would rename all seventy-odd single-output columns for
116
+ nothing. Reported by a consumer that hit the throw at module load and
117
+ worked around it by hand. No API change: the descriptors, the studies and
118
+ the guard are all unchanged, and the round-trip test is what stops the two
119
+ packages drifting — `catalog.test.ts` validates a descriptor against its
120
+ *study*, so it is structurally blind to a cross-package disagreement.
121
+ - `@pond-ts/process`: **`Skipped.spec` echoes the request verbatim**, and its
122
+ `params` / `inputs` are typed `unknown` accordingly. The plan pass normalized
123
+ `params: null` to `{}`, so recomputing an id from the echo produced the
124
+ _defaulted spec's valid id_ — keying a broken persisted entry's report onto a
125
+ legitimate node. The selector pass echoed the original all along, so the two
126
+ passes disagreed. **Migration:** a consumer reading `entry.spec.params` now
127
+ narrows it (`entry.spec.params as Record<string, unknown>`, or a guard) —
128
+ which is the point, since the value may be exactly the malformed thing that
129
+ failed.
130
+ - `@pond-ts/process`: `specId(…, { validate: false })` is **total over
131
+ arbitrary JSON**, not just over well-typed specs. `params: null`, a
132
+ non-array `inputs`, and an input entry that is neither a column name nor a
133
+ spec each used to raise a `TypeError`; they are now named in the `p1?:`
134
+ namespace, distinctly enough that two differently-broken specs stay two ids.
135
+ Strict mode reports them as `ParamError` / `ArityError` / `ProcessError`
136
+ rather than crashing.
137
+
138
+ (All three reported by Tidal against 0.62.0, after adopting it.)
139
+
140
+
141
+ ## [0.69.0] — 2026-09-13
142
+
143
+ ### Added
144
+
145
+ - **`<ChartContainer timeZone>` — the time axis in any IANA zone
146
+ ([PND-TZAXIS]).** Day / week / month ticks land on that zone's midnights,
147
+ Mondays and month starts; labels, the stacked date bands, the hierarchical
148
+ grid, session dividers and every cursor / marker / annotation readout read
149
+ in it. **Omitted ⇒ the viewer's zone**, exactly as before. The d3 specifier
150
+ strings on `timeFormat` / `cursorFormat` are unchanged; `%Z` / `%z` now read
151
+ the zone's abbreviation / offset. Sub-day ticks align to the zone's wall
152
+ clock, so a 6 h grain reads 00 / 06 / 12 / 18 across a DST jump instead of
153
+ drifting by an hour until the next midnight. The resolved zone is on the
154
+ chart context as `timeZone`. Built on core's `TimeZone` ([PND-TZCAL]), so a
155
+ `Sequence.calendar('day', { timeZone })` bucket edge and the tick that
156
+ labels it are one instant — pinned by a cross-package test.
157
+ - **`<XAxis timeZone>` — a second strip in another zone.** Two time axes
158
+ over one shared mapping, each ticking and labelling (and pilling) in its
159
+ own zone: `<XAxis side="top" timeZone="America/New_York" />` above a
160
+ UTC container's own strip below. Backed by
161
+ `TradingTimeScale.withTimeZone(zone)` / `.timeZone()` and an optional
162
+ `DiscontinuityProvider.withTimeZone` (the identity provider re-derives its
163
+ day anchors; a trading calendar's session opens are zone-independent).
164
+ - **`TradingCalendarLike.timeZone?`** — a calendar that carries its exchange
165
+ zone supplies the axis default (`calendar={cal}` renders in exchange time
166
+ wherever it is viewed); an explicit `timeZone` prop wins.
167
+ - `scaleTradingTime(provider, { timeZone })` and
168
+ `identityProvider({ timeZone })` take the zone directly for consumers
169
+ building the scale themselves; `identityProvider`, `TradingCalendarLike`
170
+ and `ScaleTimeZoneOptions` are now exported. Internally the tick ladder
171
+ runs on a `TickCalendar` seam whose local implementation is the previous
172
+ `Date` arithmetic verbatim — the default path is unchanged.
173
+ - **`TradingCalendar.timeZone` ([PND-TZFIN]).** `@pond-ts/financial`'s
174
+ calendar keeps the zone its sessions were resolved in — `fromRules` carries
175
+ `rules.timeZone`, `fromSessions(list, { timeZone })` takes it — so
176
+ `<ChartContainer calendar={cal}>` renders the axis in exchange time with no
177
+ further wiring.
178
+ - `@pond-ts/charts` now depends on `d3-time-format` directly (it was already
179
+ a transitive dependency via `d3-scale`).
180
+ - **`TimeZone` — the zone-calendar primitive ([PND-TZCAL]).** `pond-ts`
181
+ exports `TimeZone.of(id)` (interned; also `TimeZone.UTC`,
182
+ `TimeZone.local()`) with `startOf(unit, t)`, `next(unit, t)`, `parts(t)`,
183
+ `instant(parts, { disambiguation })`, `offsetAt(t)` and
184
+ `abbreviation(t, { locale })`. Temporal underneath, but each zone caches its
185
+ offset transitions as it discovers them, so steady-state calls are integer
186
+ arithmetic: `startOf('day')` went from ~24 µs to ~23 ns per call, and a
187
+ three-year hourly series aggregated to `America/New_York` days from 38 ms
188
+ to 0.5 ms. `Sequence.calendar`, `TimeRange.fromCalendar` and
189
+ `Interval.fromCalendar` now bucket through it (no behaviour change; pinned
190
+ against Temporal on eight zones including southern-hemisphere DST, a
191
+ 30-minute DST shift, a +05:30 zone, a day with no midnight and Samoa's
192
+ skipped day). This is the primitive the charts' time axis will place and
193
+ label ticks with, so a bucket edge and the tick that labels it are one
194
+ instant. First task of the time-zone plan
195
+ (`docs/plans/PND_TIMEZONE_PLAN.md`).
196
+ - **`CalendarUnit` gains `'quarter'` and `'year'`** for
197
+ `Sequence.calendar`, `TimeRange.fromCalendar` and `Interval.fromCalendar`.
198
+
199
+ ### Changed
200
+
201
+ - **`Sequence.calendar` validates its inputs at construction.** An unknown
202
+ unit (`'hour'`) or zone (`'Nowhere'`) now throws `RangeError` immediately;
203
+ before, an unknown unit silently produced wrong buckets (the two unit
204
+ dispatchers fell through to different defaults — the 2026-06 audit's §6
205
+ finding) and an unknown zone failed only on first `bounded()`.
206
+
207
+ ### Fixed
208
+
209
+ - **`pond-ts`: two type-level corners of [PND-PARTCOL] (0.68.0) found by the Codex pass on #724.** (1) On a broad `TimeSeries<SeriesSchema>` with a _literal_ partition column, the injected `'first'` could not look up a kind and typed the column as `undefined`; `WithPartitionColumns` now takes the schema and leaves the mapping alone when the schema is broad, so the result type is exactly 0.67's. (2) `By` had no variance pin, so `PartitionedTimeSeries<S, K, 'host'>` accepted a view partitioned by `region` (and an untyped view could be narrowed to any column); a phantom contravariant member now rejects both while a specialised view still assigns to the legacy `PartitionedTimeSeries<S>` shape. Type tests cover both plus the `K`-survives-`smooth`/`baseline` claim. No runtime change.
210
+ - **Docs said a wall-clock string without `parse.timeZone` throws. It never
211
+ did** ([PND-TZDOCS]) — it is read as UTC, silently. `creating.mdx`, the
212
+ agent guide (`AGENTS.md`) and the decision table now say so and describe
213
+ how the shift shows up. The agent guide also gains the one time-zone rule:
214
+ pass the same `timeZone` to `Sequence.calendar` and `<ChartContainer>`.
215
+ The aggregation page cross-links `Sequence.calendar` for weekly / monthly
216
+ bars (issue #358 item 1, supersedes #359). The finance gallery's off-chart
217
+ readout takes the calendar's zone instead of hard-coding New York; the
218
+ Niño 3.4 heat map's year grain uses `Sequence.calendar('year')`.
219
+
74
220
  ## [0.68.0] — 2026-09-13
75
221
 
76
222
  ### Added
package/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @pond-ts/fit
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/@pond-ts/fit?label=%40pond-ts%2Ffit)](https://www.npmjs.com/package/@pond-ts/fit)
4
+ [![CI](https://github.com/pond-ts/pond/actions/workflows/ci.yml/badge.svg)](https://github.com/pond-ts/pond/actions/workflows/ci.yml)
5
+ [![docs](https://img.shields.io/badge/docs-pond--ts.org-1f6feb)](https://pond-ts.org/docs/fit/)
6
+
3
7
  **Fitness & activity analytics on [pond-ts](https://www.npmjs.com/package/pond-ts).**
4
8
 
5
9
  Turn raw activity streams (GPS, power, heart rate, cadence, …) into a typed,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pond-ts/fit",
3
- "version": "0.68.0",
3
+ "version": "0.70.0",
4
4
  "private": false,
5
5
  "description": "Fitness & activity domain library on pond-ts: typed quantities, canonical activity series, and analytics (geo distance/elevation, power NP/IF/TSS, zones, splits)",
6
6
  "keywords": [
@@ -59,7 +59,7 @@
59
59
  "verify": "npm run format:check && npm run build && npm test"
60
60
  },
61
61
  "peerDependencies": {
62
- "pond-ts": "^0.68.0"
62
+ "pond-ts": "^0.70.0"
63
63
  },
64
64
  "devDependencies": {
65
65
  "typescript": "^5.6.3",