changelog: updated

This commit is contained in:
nym21
2026-03-23 18:30:32 +01:00
parent ade23795b8
commit 000027fab8
+262
View File
@@ -4,6 +4,268 @@ All notable changes to the Bitcoin Research Kit (BRK) project will be documented
> *This changelog was generated by Claude Code*
## [v0.2.1](https://github.com/bitcoinresearchkit/brk/releases/tag/v0.2.1) - 2026-03-23
### Breaking Changes
#### `brk_rpc`
- Made `corepc` the default feature — `brk_rpc` now uses the `brk-corepc-client` RPC backend by default instead of requiring explicit feature opt-in; users relying on `bitcoincore-rpc` must now explicitly enable it ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.1/crates/brk_rpc/Cargo.toml))
[View changes](https://github.com/bitcoinresearchkit/brk/compare/v0.2.0...v0.2.1)
## [v0.2.0](https://github.com/bitcoinresearchkit/brk/releases/tag/v0.2.0) - 2026-03-23
This is a major architectural release. The most significant changes are:
1. **Self-contained, oracle-only pricing**: The computation pipeline no longer uses exchange APIs for price data. All prices are now derived on-chain via the `brk_oracle` crate from block 550,000 onward, with pre-computed historical prices embedded for earlier blocks. `brk_fetcher` remains as a crate but is no longer used by `brk_computer` or `brk_cli`. Bitcoin Core is now the only runtime dependency — the toolkit runs fully offline and produces deterministic, reproducible results.
2. **Height-only storage**: All series now store only the per-block (height-indexed) vec on disk. Previously each series stored both a height vec and a date-indexed vec. All non-height resolutions (minute10 through year10, halving, epoch — 15 total, up from 8) are now computed lazily on demand from the height data using `LazyAggVec` with flat height-to-period mappings. This roughly halves on-disk vec count while nearly doubling the number of available resolutions.
3. **Flat index architecture**: The old cascading index hierarchy (height → date → week → month → quarter → year → decade) is replaced by a flat system where every period type maps directly to Height. This eliminates intermediate stored mappings and enables sub-day resolutions (10min, 30min, 1h, 4h, 12h) that were previously impossible.
4. **Profitability cohorts**: New UTXO bucketing by unrealized profit/loss percentage — 25 ranges from ">1000% in profit" to "90-100% in loss", plus 14 aggregate profit thresholds and 9 loss thresholds, powered by a 190K-bucket Fenwick tree for O(log N) per-block computation.
As a consequence of height-only storage, temporal aggregation shifted from date-based (daily sum, daily last, daily cumulative) to **rolling windows** (24h, 1w, 1m, 1y) computed from height data using precomputed lookback start positions (`CachedWindowStarts`). Most series now expose a `block` value, `cumulative` sum, and `RollingComplete` (rolling sums + rolling averages + rolling distribution with min/max/median/percentiles per window) — all derived from the single height vec.
Resolution data is served through a popularity-based caching layer: up to 256 height-source vecs are cached in memory with LRU eviction based on access frequency, while period-to-height index mappings are always cached since they're small and shared across all series.
### Breaking Changes
#### `brk_types`
- Renamed all `Address`/`Addresses` types to `Addr`/`Addrs` across the entire public API: `Address``Addr`, `AddressBytes``AddrBytes`, `AddressHash``AddrHash`, `AddressStats``AddrStats`, `AddressChainStats``AddrChainStats`, `AddressMempoolStats``AddrMempoolStats`, `AddressParam``AddrParam`, `AddressValidation``AddrValidation`, `AnyAddressIndex``AnyAddrIndex`, `FundedAddressData``FundedAddrData`, `EmptyAddressData``EmptyAddrData`, etc. ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_types/src/addr.rs))
- Renamed all `Metric`/`Metrics` types to `Series`: `MetricParam``SeriesParam`, `MetricData``SeriesData`, `MetricOutput``SeriesOutput`, `MetricCount``SeriesCount`, `MetricSelection``SeriesSelection`, `MetricsPaginated``SeriesPaginated`, `MetricWithIndex``SeriesNameWithIndex` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_types/src/series_data.rs))
- Renamed `DateIndex` to `Day1` and removed `DecadeIndex`, `WeekIndex`, `MonthIndex`, `QuarterIndex`, `SemesterIndex`, `YearIndex` — replaced with a comprehensive resolution system: `Minute10`, `Minute30`, `Hour1`, `Hour4`, `Hour12`, `Day1`, `Day3`, `Week1`, `Month1`, `Month3`, `Month6`, `Year1`, `Year10` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_types/src/day1.rs))
- Renamed `DifficultyEpoch` to `Epoch` and `HalvingEpoch` to `Halving` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_types/src/epoch.rs))
- Renamed `CentsUnsigned` to `Cents` and `CentsUnsignedCompact` to `CentsCompact` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_types/src/cents.rs))
- Adopted snake_case for all module file names (e.g. `blockinfo``block_info`, `blocktimestamp``block_timestamp`, `feeratepercentiles``feerate_percentiles`, `txstatus``tx_status`, `poolslug``pool_slug`, etc.)
#### `brk_computer`
- **All series now store height-indexed data only on disk** — previously each metric stored both a `height: EagerVec` and a `dateindex: EagerVec` (and sometimes cumulative/sum variants at each level). Now `PerBlock<T>` has `height: EagerVec` + `resolutions: Box<Resolutions<T>>` where all 15 resolutions are `LazyAggVec` instances computed on demand. This roughly halves the on-disk vec count per series ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/internal/per_block/computed/base.rs))
- **Replaced cascading index hierarchy with flat height-to-period mappings** — old system chained height→dateindex→weekindex→monthindex→yearindex→decadeindex; new system maps every period type directly to Height via `EagerIndexes`, enabling all resolutions to derive from height data without intermediate stored vecs ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/indexes/mod.rs))
- Restructured `internal/` SDK from `single`/`multi` hierarchy to concept-oriented modules: `per_block/`, `per_tx/`, `algo/`, `transform/`, `containers/`, `indexes/` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/internal/mod.rs))
- Moved `blocks/mining/` and `blocks/rewards/` into a dedicated top-level `mining/` module with `rewards/` and `hashrate/` sub-modules ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/mining/mod.rs))
- Moved `market/indicators/` to a top-level `indicators/` module with expanded scope ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/indicators/mod.rs))
- Renamed `price` module to `prices` with restructured sub-modules: `by_unit.rs` (multi-currency structs), `ohlcs.rs` (OHLC aggregation), `compute.rs` (oracle-based price computation) ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/prices/mod.rs))
- Renamed `cointime/pricing` to `cointime/prices` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/cointime/prices/mod.rs))
- Renamed `distribution/address` to `distribution/addr` and `distribution/cohorts/address` to `distribution/cohorts/addr`
- Replaced all `Clone`-derived `Vecs` structs with generic `StorageMode` parameter (`Vecs<M: StorageMode = Rw>`) across every computation module (blocks, transactions, market, distribution, supply, etc.) for type-safe read-only sharing
- Removed `brk_fetcher` dependency — price computation is now fully on-chain via the oracle, eliminating exchange API calls (Binance, Kraken) and the 12-hour retry/HAR-import fallback logic
- Removed `traits/` module (pricing traits) and `utils.rs`
- `Computer::forced_import` no longer accepts a `Fetcher` parameter — signature simplified from `(path, indexer, fetcher)` to `(path, indexer)`
- Restructured all market sub-modules with new type-safe containers replacing ad-hoc naming: `price_1w_sma``sma._1w`, `price_ath``high`, `price_drawdown``drawdown`, `price_returns``periods`, `price_ago``price_past`, etc.
- Restructured ATH vecs: `price_ath``high.cents`, `price_drawdown``drawdown`, `days_since_price_ath``days_since`, `max_days_between_price_aths``max_days_between` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/market/ath/vecs.rs))
- Restructured DCA vecs: split into `PeriodVecs` (stack, cost_basis, return, cagr, lump_sum) and `ClassVecs` (stack, cost_basis, return), removing explicit days-in-profit/loss and min/max return fields ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/market/dca/vecs.rs))
- Restructured volatility vecs: replaced individual `price_Xw_volatility`, `sharpe_Xw`, `sortino_Xw` fields with `Windows<LazyPerBlock<StoredF32>>` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/market/volatility/vecs.rs))
- Restructured returns vecs: replaced individual period fields with `ByLookbackPeriod<PercentPerBlock>`, added `sd_24h: Windows<StdDevPerBlock>` replacing explicit 1w/1m/1y standard deviation and downside fields ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/market/returns/vecs.rs))
- Restructured range vecs: replaced 8 individual min/max price fields with `PriceMinMaxVecs` containing `min`/`max` groups, and added choppiness index as `PercentPerBlock` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/market/range/vecs.rs))
- Restructured moving average vecs: split into `SmaVecs` and `EmaVecs` using `PriceWithRatioPerBlock<M>` for each period, added Mayer Multiple bands (`_200d_x2_4`, `_200d_x0_8`) ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/market/moving_average/vecs.rs))
- Restructured burned supply: merged `opreturn` and `unspendable` into single `total: AmountPerBlockCumulative` with inline computation ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/supply/burned/vecs.rs))
- Restructured transaction volume: replaced `sent_sum`/`received_sum`/`annualized_volume` with single `transfer_volume: AmountPerBlockCumulativeRolling`, wrapped throughput metrics in `Windows<PerBlock>` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/transactions/volume/vecs.rs))
- Removed `distribution/compute/aggregates.rs` — aggregate computation moved into metric tiers
- Removed `distribution/range_map.rs` — range mapping moved to `brk_types::RangeMap`
#### `brk_query`
- Renamed `address()`/`address_txids()`/`address_utxos()` methods to `addr()`/`addr_txids()`/`addr_utxos()` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_query/src/impl/addr.rs))
- Renamed `metrics` query module to `series` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_query/src/impl/series.rs))
- Removed `resolved.rs` — resolution handling moved inline
#### `brk_server`
- Renamed `/api/address/*` routes and `AddressRoutes` trait to `AddrRoutes` (redirects preserved from old paths) ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_server/src/api/addrs/mod.rs))
- Renamed `/api/series/*` routes (previously `/api/metrics/*`) — legacy `/api/metrics/*` routes preserved as redirects ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_server/src/api/series/mod.rs))
- Removed `brk_fetcher` dependency
- Removed `Client` from `AppState` — server no longer holds a direct RPC client reference
#### `brk_client`
- Switched HTTP backend from `minreq` to `ureq`
- Removed `fetch_prices.rs` example
#### `brk_fetcher`
- Switched HTTP backend from `minreq` to `ureq`
#### `brk_rpc`
- Added `corepc` feature integrating `brk-corepc-client` and `brk-corepc-jsonrpc` as alternative RPC backends ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_rpc/Cargo.toml))
#### `brk_cohort`
- Renamed `AddressGroups` to `AddrGroups` with renamed fields: `ge_amount``over_amount`, `lt_amount``under_amount`, `ByGreatEqualAmount``OverAmount`, `ByLowerThanAmount``UnderAmount`, `ByAmountRange``AmountRange` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_cohort/src/addr.rs))
- Renamed `ByAgeRange` to `AgeRange` with renamed fields: `up_to_1h``under_1h`, `from_15y``over_15y` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_cohort/src/age_range.rs))
- Renamed file names from concatenated (`by_age_range.rs`, `by_amount_range.rs`) to snake_case (`age_range.rs`, `amount_range.rs`)
### New Features
#### `brk_computer`
- Added `indicators/` module computing on-chain indicators: Puell Multiple, RHODL Ratio, NVT Ratio, Thermocap Multiple, Supply-Adjusted CDD, Supply-Adjusted CYD, Supply-Adjusted Dormancy, Dormancy Flow, Stock-to-Flow, Seller Exhaustion Constant, and Gini coefficient ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/indicators/compute.rs))
- Added `mining/` module with dedicated hashrate computations: hash rate with 1w/1m/2m/1y SMAs, hash rate ATH and drawdown, hash price and hash value per TH/s and PH/s, hash price/value minimums and rebound metrics ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/mining/hashrate/compute.rs))
- Added `mining/rewards/` with coinbase rewards, subsidy, fee dominance, unclaimed rewards — each with block/cumulative/rolling views and sats/btc/usd units ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/mining/rewards/compute.rs))
- Added `market/technical/` module implementing RSI with Stochastic RSI (RSI, StochRSI, K-line, D-line with configurable RMA/SMA periods) and MACD (fast/slow EMA, signal line, histogram) ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/market/technical/rsi.rs))
- Added Fenwick tree (Binary Indexed Tree) data structure supporting O(log N) point-update, prefix-sum, and multi-target kth walk-down queries ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/internal/algo/fenwick.rs))
- Added `ExpandingPercentiles` tracker using Fenwick tree for O(log N) percentile queries with 0.1% resolution, supporting bulk-load initialization ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/internal/algo/expanding_percentiles.rs))
- Added `CostBasisFenwick` — 4-field Fenwick tree (all_sats, sth_sats, all_usd, sth_usd) for per-block accurate cost basis percentiles, supply density queries (±5% of spot price), and profitability range computation across 25 ranges with all/STH splits ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/distribution/cohorts/utxo/fenwick.rs))
- Added sliding distribution, sliding median, sliding window, and drawdown algorithms in `internal/algo/` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/internal/algo/mod.rs))
- Added `Resolutions<T>` — a `PerResolution` of 15 `LazyAggVec` instances that lazily derive all supported resolutions from a single height-indexed source vec, using flat height-to-period mappings and a "last value in period" aggregation strategy ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/internal/per_block/computed/resolutions.rs))
- Added `DerivedResolutions<T, S1T>` — doubly-lazy resolution system for `LazyPerBlock` that chains `UnaryTransform` on top of source resolutions, enabling zero-storage derived series at all 15 resolutions ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/internal/per_block/lazy/derived_resolutions.rs))
- Added popularity-based resolution caching: `CachedVec` wrapping with a global budget of 256 slots, minimum 2 accesses before caching, and LRU eviction that replaces the least-accessed cached vec when a more popular one requests caching ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/internal/cache_budget.rs))
- Added `prices/` module with `SplitByUnit` (open/high/low/close in USD/cents/sats), `OhlcByUnit`, and `PriceByUnit` structured types for multi-currency price access ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/prices/by_unit.rs))
- Added `ProfitabilityMetrics` computing per-block supply, realized cap, unrealized PnL, and NUPL across 25 profitability ranges plus 14 profit thresholds and 9 loss thresholds, each with all/STH splits ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/distribution/metrics/profitability.rs))
- Restructured distribution metrics into trait-based tiered system with `ActivityLike`, `RealizedLike`, `UnrealizedLike` trait hierarchies — each metric type has core/basic/minimal/full variants enabling flexible per-cohort metric composition ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/distribution/metrics/cohort/mod.rs))
- Added `distribution/metrics/relative/` sub-module with 6 variants: `RelativeToAll`, `RelativeForAll`, `RelativeWithExtended`, `RelativeFull`, `RelativeExtendedOwnMarketCap`, `RelativeExtendedOwnPnl` for cohort-to-total ratio metrics ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/distribution/metrics/relative/mod.rs))
- Added `distribution/addr/activity.rs` tracking per-block address activity counts (receiving, sending, reactivated, both) globally and per address type, with rolling averages ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/distribution/addr/activity.rs))
- Added `distribution/addr/delta.rs` computing rolling address count deltas with change magnitude and basis-point rates ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/distribution/addr/delta.rs))
- Added `distribution/state/pending.rs` with `PendingDelta`, `PendingCapDelta`, `PendingInvestorCapDelta` for batched cost basis state updates
- Added maturation tracking to age cohorts: `tick_tock_next_block` now returns `AgeRange<Sats>` tracking how many sats mature from each age range into the next older one per block, stored as `matured: AgeRange<AmountPerBlockCumulativeRolling>` on `UTXOCohorts` with cumulative and rolling window views for all 21 age ranges ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/distribution/cohorts/utxo/tick_tock.rs))
- Added `pools/major.rs` and `pools/minor.rs` separating major pools (with cumulative rolling rewards and dominance rolling windows) from minor pools (blocks mined with cumulative rolling and dominance ratio) ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_computer/src/pools/major.rs))
- Added `blocks/lookback.rs` for precomputed rolling window lookback start vectors used across all windowed computations
- Added `cache_budget.rs` system for managing memory cache allocation across vecs
- Added `tree.rs` example for inspecting the full series tree structure
#### `brk_types`
- Added 11 new resolution index types expanding from 8 resolutions (day, week, month, quarter, semester, year, decade, difficulty epoch) to 15: `Minute10`, `Minute30`, `Hour1`, `Hour4`, `Hour12` (sub-day — entirely new), `Day3`, `Month3`, `Month6` (new intermediate periods), `Year10` (replaces decade), plus renamed `Day1` (was DateIndex), `Week1` (was WeekIndex), `Month1` (was MonthIndex), `Year1` (was YearIndex), `Halving` (was HalvingEpoch), `Epoch` (was DifficultyEpoch) ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_types/src/hour1.rs))
- Added `FromCoarser` trait enabling automatic derivation of finer-grained resolution data from coarser sources ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_types/src/from_coarser.rs))
- Added basis points types: `BasisPoints16`, `BasisPoints32`, `BasisPointsSigned16`, `BasisPointsSigned32` for precision ratio/percentage storage without floating point ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_types/src/basis_points_32.rs))
- Added `StoredI64` type for signed 64-bit stored values ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_types/src/stored_i64.rs))
- Added `RangeIndex` and `RangeMap` types for range-based lookups ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_types/src/range_index.rs))
- Added `SearchQuery` type for series full-text search ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_types/src/search_query.rs))
- Added `SeriesInfo` type carrying metadata about each data series ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_types/src/series_info.rs))
- Added `DataRange` as a dedicated type (previously inline) ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_types/src/data_range.rs))
- Added `pools-v2.json` with expanded mining pool identification data
- Added `SeriesList` and `SeriesName` types for typed series enumeration
#### `brk_server`
- Added structured JSON error responses with RFC 9457-inspired format: `type` (error category), `code` (machine-readable), `message` (human-readable), `doc_url` (link to API docs) — covers all BRK error variants with proper HTTP status mapping ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_server/src/error.rs))
- Added `X-Response-Time` header (in microseconds) on all responses for latency observability
- Added Vary header consolidation middleware merging duplicate Vary headers into a single comma-separated value
- Added custom panic handler extracting panic messages into structured JSON error responses instead of empty 500s
- Added `ContentEncoding` module with server-side content encoding negotiation (zstd > br > gzip > identity) and transparent pre-compression of cached responses via brotli, flate2, and zstd ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_server/src/extended/encoding.rs))
- Added pre-compressed Brotli encoding for the Scalar API documentation viewer (`scalar.js.br`) ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_server/src/api/scalar.js.br))
- Extracted `finish_openapi()` and `generate_bindings()` as public functions for external use ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_server/src/lib.rs))
- Made `ApiRoutes` trait public for external router composition
#### `brk_query`
- Added `list.rs` example for enumerating all available series names ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_query/examples/list.rs))
#### `brk_cohort`
- Added `ProfitabilityRange<T>` with 25 buckets from ">1000% in profit" to "90-100% in loss", with boundary prices computed dynamically from spot price via `compute_profitability_boundaries()` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_cohort/src/profitability_range.rs))
- Added `Profit<T>` with 14 aggregate "at least X% profit" thresholds (prefix sums over ranges) and `Loss<T>` with 9 aggregate "at least X% loss" thresholds (suffix sums over ranges) ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_cohort/src/profit.rs))
- Added `AgeRange::from_array()` constructor for building age range structs from fixed-size arrays ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_cohort/src/age_range.rs))
- Derived `Traversable` on `AddrGroups` via proc macro (previously manual `Traversable` impl on `AddressGroups`)
#### `brk_traversable`
- Added `iter_any_visible()` method to the `Traversable` trait — allows structs to expose all vecs for disk operations while hiding some from the public series tree ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_traversable/src/lib.rs))
- Added `Traversable` impls for `LazyAggVec`, `LazyDeltaVec`, `ReadOnlyCompressedVec`, `ReadOnlyRawVec` — enabling lazy and read-only vecs to appear in the series tree
#### `brk_traversable_derive`
- Added `#[traversable(hidden)]` attribute at struct and field level — hidden structs return empty tree nodes and empty `iter_any_visible()` while still participating in `iter_any_exportable()` for disk I/O ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_traversable_derive/src/lib.rs))
- Added automatic `ReadOnlyClone` derive generation — the proc macro now generates `impl ReadOnlyClone` alongside `impl Traversable`, mapping `Rw` to `Ro` storage mode for all fields with `StorageMode` parameters
- Added multi-level `wrap` paths (`#[traversable(wrap = "a/b")]`) for creating nested tree structure
- Preserved struct field declaration order in tree key ordering (previously normal and flattened fields were separated)
#### `brk_oracle`
- Lowered `START_HEIGHT` from 575,000 to 550,000 — oracle begins computing 25,000 blocks earlier ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_oracle/src/lib.rs))
#### `brk_reader`
- Added timestamp-based pre-filtering in block decoding — blocks are skipped by header timestamp before computing block hash, avoiding expensive RPC calls for out-of-range blocks ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_reader/src/lib.rs))
- Added `find_magic()` function with XOR-decoded sliding window for blk file scanning, replacing byte-by-byte loop
- Replaced batch-based block decoding pipeline (accumulated blocks, sleep-based backpressure) with direct `par_bridge()` streaming — simpler, no sleep delays
#### `brk_bindgen`
- Added template-based pattern system with discriminator support — `try_detect_template()` handles suffix discriminators (e.g. `ratio_sd` vs `ratio_sd_4y`) and embedded discriminators (e.g. `ratio_pct99_bps` vs `ratio_pct1_bps`) for smarter client code generation ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.2.0/crates/brk_bindgen/src/analysis/positions.rs))
- Added two-pass field part analysis: first pass collects instance analyses bottom-up, second pass fills mixed-empty field parts using shortest leaf names
- Added `owned_expr()`, `disc_arg_expr()`, `template_expr()` to `LanguageSyntax` trait for language-specific discriminator formatting
- Fixed pattern normalization to only erase leaf types when all leaves share the same type (prevents incorrect genericization of mixed-type signatures)
#### `brk_client` (Rust)
- Switched HTTP backend from `minreq` to `ureq`
- Removed `fetch_prices.rs` example
#### `brk_client` (JavaScript)
- Added `tests/consistency.js` — verifies all series sharing the same index have the same length (catches stale state after reorg rollback)
- Upgraded `quickmatch` 0.3.1 → 0.4.0: expanded default separators (`_- :/`), added prefix indexing and compound word indexing (e.g. "hashrate" now matches "hash_rate"), added `minScore` threshold to reduce false positives, replaced per-match object allocation with pre-allocated `Uint32Array` scoring
#### `brk_client` (Python)
- Added `DateSeriesData` subclass with date-aware methods (`.dates()`, `.date_items()`, `.to_date_dict()`) — date-based indexes return `DateSeriesData`, non-date indexes return `SeriesData`
- Added new API methods: `get_series_data()`, `get_series_latest()`, `get_series_len()`, `get_series_version()`, `date_to_index()`
- Added `DetailedSeriesCount` with `distinct_series`, `total_endpoints`, `lazy_endpoints`, `stored_endpoints` fields
- Added `ErrorDetail`/`ErrorBody` types matching the server's structured error responses
- Range parameters now accept `date` and `datetime` objects in addition to integers
### Internal Changes
#### `brk_computer`
- Rewrote the `internal/` SDK: replaced the `single`/`multi` hierarchy (160+ files with per-combination types like `lazy_binary_computed_full`, `value_lazy_sum_cum`, `ComputedFromHeightAndDateLast`, `ComputedFromHeightSumCum`) with a composable system organized by concept (`per_block/`, `per_tx/`, `algo/`, `transform/`, `containers/`, `indexes/`). Concrete example: block count went from ~15 on-disk vecs (`ComputedFromHeightSumCum` + 4 rolling start vecs + 4 `ComputedFromHeightLast`) down to ~2 on-disk vecs (`PerBlockCumulativeRolling`) with all resolutions lazy
- Added `UnaryTransform` trait system in `internal/transform/` replacing ad-hoc closures: `arithmetic.rs`, `bps.rs`, `currency.rs`, `derived.rs`, `ratio.rs`, `specialized.rs`
- Added container types in `internal/containers/`: `per_resolution`, `windows`, `windows_from_1w`, `windows_to_1m`, `window_24h`, `distribution_stats`, `constant`, `percent`
- Added per-block type variants: `PerBlock`, `PerBlockFull`, `PerBlockCumulative`, `PerBlockCumulativeWithSums`, `PerBlockRolling`, `PerBlockAggregated`, `LazyPerBlock`, `LazyPerBlockRolling`, plus `AmountPerBlock`, `AmountPerBlockCumulative`, `AmountPerBlockCumulativeRolling`, `AmountPerBlockWithDeltas`, `FiatPerBlock`, `PercentPerBlock`, `RatioPerBlock`, `PerBlockRollingAverage`, `PercentRollingWindows`, `PriceWithRatioPerBlock`, `StdDevPerBlock`
- Added rolling types: `RollingComplete`, `LazyRollingComplete`, `RollingDistribution`, `LazyRollingSums`, `LazyRollingDeltasFromHeight`
- Added per-tx types: `PerTxDerived`, `PerTxDistribution`, `LazyPerTxDerived`, `LazyPerTxDistribution`, `LazyPerTxDistributionTransformed`
- Added eager/lazy index helpers in `internal/indexes/`
- Introduced `CachedWindowStarts` for shared precomputed lookback window start positions across all modules
- Split distribution UTXO cohort vecs into `core.rs`, `minimal.rs`, `type.rs` sub-modules for tiered storage
- Added `sum_others` macro in distribution metrics for computing aggregate cohort fields by summing constituent cohorts
- Removed `brk_fetcher` dependency — oracle prices are computed directly in the `prices/` module
- Removed `distribution/compute/aggregates.rs` — aggregate computation replaced by `compute_from_stateful` / `compute_sum_of_others` within each metric tier
#### `brk_indexer`
- Bumped reindex version 24 → 25 (forces full reindex on upgrade)
- Added `StorageMode` generic parameter on `Indexer<M>` and `Vecs<M>` with `ReadOnlyClone` impl producing `Indexer<Ro>` for type-safe read-only sharing
- Parallelized block processing pipeline: inputs and outputs now processed in parallel via `rayon::join`, finalization of outputs+inputs runs in parallel with tx metadata storage
- Added `BlockBuffers` struct with reusable `FxHashMap`/`FxHashSet` allocations cleared per block, eliminating per-block allocation overhead
- Added `AddrTypeVecs<I, B>` and `ScriptTypeVecs<I>` generic sub-structs for uniform per-type vec organization, replacing individually named fields
- Added `TxMetadataVecs` sub-struct with `split_for_finalize()` for separating tx metadata vecs from index vecs during parallel finalization
- Added `AddrReaders` with `script_pubkey(&self, output_type, type_index) -> ScriptBuf` for typed address-to-script lookup
- Block size and weight now computed from pre-computed `ComputedTx.base_size`/`total_size` fields instead of re-serializing transactions
- Removed 512MB thread stack size workaround — main function runs directly
- Added `schemars` and `serde` dependencies for OpenAPI-compatible schema generation
#### `brk_server`
- Applied `NormalizePathLayer` as an outer wrapping layer (via `ServiceExt`) instead of an inner router layer, fixing route matching for trailing slashes
- Reduced in-memory response cache from 5,000 to 1,000 entries
- Moved `CatchPanicLayer` after compression in the middleware stack with a custom handler
- Restructured response caching to include content encoding in cache keys, pre-compressing responses per-encoding for cache-friendly serving
- Added `brotli`, `flate2`, and `zstd` dependencies for server-side compression
- Added `color-eyre` for panic reporting
#### `brk_query`
- Removed thread stack-size workaround in the query example — main function now runs directly
- Added `parking_lot` and `serde_json` dependencies
#### `brk_rpc`
- Added `serde` and `serde_json` dependencies for `corepc` feature
#### `brk_store`
- Removed `insert_if_needed()` and `remove_if_needed()` — callers now use plain `insert()`/`remove()`
- Changed `clear_caches()` to drop allocations entirely (`FxHashMap::default()`) instead of clearing in place
#### `brk_reader`
- Removed batch-based block decoding pipeline — simplified to streaming `par_bridge()`
- Removed `AnyBlock` enum, replaced with `decode_block()` standalone function
- Added `find_magic()` with XOR-decoded sliding window for efficient blk file scanning
#### `brk_logger`
- Replaced `EnvFilter` with `Targets` for simpler log filter configuration
- Separated `LOG` (default level) from `RUST_LOG` (full directive control) environment variables
- Added `corepc=off` to default filter list
#### `brk_error`
- Added `brk-corepc-client` and `ureq` error conversions, removed `minreq` error conversions
#### `brk_cli`
- Removed `--fetch` CLI flag and `brk_fetcher` dependency — price fetching handled by the oracle
- Removed 512MB thread stack size workaround
#### `docker`
- Switched base image from `rustlang/rust:nightly` to `rust:1.93-bookworm` (stable, pinned)
- Replaced `pgrep + nc` healthcheck with `curl -sf http://localhost:3110/health`
- Removed `docker-build.sh` helper script and docker-specific `.dockerignore`
- Removed all `environment:` variables from `docker-compose.yml` — configuration now via `command:` args only
#### `scripts`
- Added `pool_major_threshold.py` — utility to determine major vs minor pool classification based on rolling dominance thresholds across multiple time windows
#### `workspace`
- Upgraded Rust toolchain to edition 2024
- Updated `.dockerignore` to exclude `docker/` directory
[View changes](https://github.com/bitcoinresearchkit/brk/compare/v0.1.9...v0.2.0)
## [v0.1.9](https://github.com/bitcoinresearchkit/brk/releases/tag/v0.1.9) - 2026-02-13
### New Features