diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index 75224c0f4..120aeedd3 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -4,6 +4,221 @@ All notable changes to the Bitcoin Research Kit (BRK) project will be documented
> *This changelog was generated by Claude Code*
+## [v0.1.9](https://github.com/bitcoinresearchkit/brk/releases/tag/v0.1.9) - 2026-02-13
+
+### New Features
+
+#### `brk`
+- Added `oracle` feature flag re-exporting `brk_oracle` from the `brk` umbrella crate, making the on-chain price oracle available via `brk::oracle` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.9/crates/brk/src/lib.rs))
+- Added `brk_oracle` to the crates table in the umbrella crate README ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.9/crates/brk/README.md))
+
+### Internal Changes
+
+#### `brk`
+- Added `brk_oracle` to the Rust publish script ordering ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.9/scripts/rust-publish.sh))
+
+[View changes](https://github.com/bitcoinresearchkit/brk/compare/v0.1.8...v0.1.9)
+
+## [v0.1.8](https://github.com/bitcoinresearchkit/brk/releases/tag/v0.1.8) - 2026-02-13
+
+### Breaking Changes
+
+#### `brk_types`
+- Renamed `Sats::is_round_btc()` to `is_common_round_value()` and rewrote the algorithm: replaces a hardcoded array of 19 specific round sat values with a general integer-based approach using `ilog10()` to detect any value matching `d × 10^n` where `d ∈ {1, 2, 3, 5, 6}` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_types/src/sats.rs))
+
+#### `brk_server`
+- Renamed `CacheStrategy::MaxAge(u64)` to `CacheStrategy::MempoolHash(u64)`, switching mempool endpoints from time-based `Cache-Control: max-age=N` to content-addressed ETags derived from the next projected block hash ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_server/src/cache.rs))
+
+### New Features
+
+#### `brk_oracle`
+- Added new `brk_oracle` crate: a pure on-chain BTC/USD price oracle that derives the bitcoin price from round-dollar transaction output patterns ($1, $5, $10, ... $10,000) without any exchange data ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_oracle/src/lib.rs))
+- Algorithm maps outputs to a log-scale histogram (2,400 bins, 200 per decade), smooths with an EMA over a 12-block ring buffer, then slides a 19-point stencil representing round-dollar spikes to find the best-fit price with parabolic sub-bin interpolation
+- Operates from height 575,000 (May 2019) onward; pre-oracle exchange prices for heights 0–630,000 included in `prices.txt` for bootstrapping
+- Median per-block error 0.10%, 95th percentile 0.55%; zero blocks exceed 10% error since 2022
+- Inspired by UTXOracle by @SteveSimple, with per-block resolution, single-pass stencil scoring, and rolling EMA operation
+
+#### `brk_computer`
+- Enabled oracle price computation with full OHLC data at all period levels (date, week, month, quarter, semester, year, decade, height, difficulty epoch) ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_computer/src/price/oracle/compute.rs))
+- Added `live_oracle()` method that seeds an oracle from the last committed price and replays recent blocks for real-time price estimation ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_computer/src/price/oracle/compute.rs))
+- Added `market_cap_growth_rate` metric: 365-day percentage change of market cap ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_computer/src/supply/vecs.rs))
+- Added `realized_cap_growth_rate` metric: 365-day percentage change of realized cap
+- Added `cap_growth_rate_diff` metric: lazy difference between market cap and realized cap growth rates
+- Added net sentiment computation for UTXO cohorts: computes greed minus pain per separate cohort, weighted average for aggregate cohorts, and dateindex for all cohorts ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs))
+
+#### `brk_server`
+- Added server-side response caching via `get_or_insert()` on `AppState`, backed by `quick_cache` with 50ms guard timeout for request deduplication ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_server/src/state.rs))
+- Added `GET /api/mempool/price` endpoint returning the current BTC/USD price in dollars, derived from on-chain round-dollar output patterns in the last 12 blocks plus mempool ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_server/src/api/mempool/mod.rs))
+- Added `CF-Connecting-IP` header detection for requests arriving from loopback addresses through Cloudflare, rewriting the socket address to apply non-loopback rate limits ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_server/src/lib.rs))
+- Switched address mempool endpoint to content-based cache invalidation using a hash of the address's mempool state
+
+#### `brk_query`
+- Added `live_price()` method returning the oracle-derived BTC/USD price, seeded from the last committed price with replay of the last window of blocks and mempool transactions ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_query/src/impl/price.rs))
+- Added `address_mempool_hash()` method returning a `u64` hash of an address's mempool state for content-based cache invalidation ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_query/src/impl/address.rs))
+
+#### `brk_mempool`
+- Added `Snapshot::next_block_hash()` returning a hash of the first projected block for content-based cache keys ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_mempool/src/projected_blocks/snapshot.rs))
+- Added `Sync::next_block_hash()` and `Sync::address_hash()` for exposing content hashes at the sync layer ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_mempool/src/sync.rs))
+
+#### `brk_types`
+- Derived `Hash` on `Sats` for use in content-based cache invalidation ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_types/src/sats.rs))
+- Derived `Hash` on `AddressMempoolStats` for per-address mempool hashing ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_types/src/addressmempoolstats.rs))
+
+#### `brk_client`
+- Added `get_live_price()` method for the `/api/mempool/price` endpoint ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_client/src/lib.rs))
+- Added `MetricsTree_Price_Oracle` struct exposing oracle price metrics (`price_cents`, `ohlc_cents`, `split`, `ohlc`, `ohlc_dollars`)
+- Added `market_cap_growth_rate`, `realized_cap_growth_rate`, and `cap_growth_rate_diff` fields to `MetricsTree_Supply`
+
+#### `website`
+- Replaced Kraken WebSocket price feed with HTTP polling to the oracle-based `/api/mempool/price` endpoint every 5 seconds, with re-poll on tab visibility change ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/website/scripts/utils/price.js))
+- Added Oracle candlestick chart under the Market section showing on-chain derived BTC/USD price ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/website/scripts/options/market.js))
+- Expanded Capitalization into a tree with Market Cap, Realized Cap, and Growth Rate sub-charts showing market cap growth rate, realized cap growth rate, and their difference
+- Added dynamic color assignment via `at(index, length)` for palette-aware spacing and `seq(keys)` for named color maps, replacing hardcoded color mappings across all chart options ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/website/scripts/utils/colors.js))
+
+### Internal Changes
+
+#### `brk_computer`
+- Flattened supply submodules (`circulating/`, `inflation/`, `market_cap/`) into the parent supply module, inlining their logic directly into `vecs.rs`, `import.rs`, and `compute.rs` ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/crates/brk_computer/src/supply/mod.rs))
+- Changed `CostBasisDistribution::serialize_iter` to accept `merged.into_iter()` and write to a path variable
+
+#### `brk_server`
+- Centralized response caching in `state.rs` with `cached_json()`, `cached_text()`, and `cached_bytes()` now accepting a `Uri` parameter for server-side cache keying, removing per-handler `GuardResult` boilerplate
+- Removed `ResponseExtended::new_text_cached()` and `new_bytes_cached()` in favor of inline handling in the state caching methods
+- Updated all API handlers to destructure `State(state)` and pass `&uri` for cache keying
+
+#### `website`
+- Split monolithic `components.css` into separate files: `main.css`, `nav.css`, `search.css`, `chart.css` for better organization
+- Converted chart option `top` and `bottom` properties from eager values to lazy functions with memoized evaluation for faster startup ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/website/scripts/options/full.js))
+- Refactored chart component: simplified pane management, converted legends from named object to array, consolidated time data into a single object with `setIndex()` and `fetch()` methods ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.8/website/scripts/chart/index.js))
+- Optimized navigation highlight tracking to only clear previously highlighted items instead of iterating all entries
+- Removed shadow divs from HTML and `
` pane
+- Removed unused utility files (`ws.js`, `date.js`, `serde.js`) and functions (`range()`, `numberToDollars()`, `numberToPercentage()`, `createShadow()`, `localhost`)
+
+#### `clients`
+- Bumped JavaScript and Python client versions
+
+[View changes](https://github.com/bitcoinresearchkit/brk/compare/v0.1.7...v0.1.8)
+
+## [v0.1.7](https://github.com/bitcoinresearchkit/brk/releases/tag/v0.1.7) - 2026-02-07
+
+### New Features
+
+#### `brk_computer`
+- Added `lower_price_band` metric per cohort, computed as realized_price² / investor_price, representing a floor price estimate ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.7/crates/brk_computer/src/distribution/metrics/realized.rs))
+- Added `upper_price_band` metric per cohort, computed as investor_price² / realized_price, representing a ceiling price estimate
+- Added `LazyBinaryPriceFromHeight` composite type for fully lazy binary price metrics providing both USD and sats representations at all time levels ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.7/crates/brk_computer/src/internal/multi/from_height/lazy_binary_price.rs))
+- Added `DollarsSquaredDivide` binary transform implementing `a² / b` for Dollars values ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.7/crates/brk_computer/src/internal/single/transform/dollars_squared_divide.rs))
+
+#### `brk_types`
+- Added `Log200` variant to `CostBasisBucket` for logarithmic bucketing with 200 buckets per decade ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.7/crates/brk_types/src/cost_basis_bucket.rs))
+- Added `From for i128` and `From for CentsSigned` conversions for wider arithmetic operations ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.7/crates/brk_types/src/cents_signed.rs))
+
+#### `brk_website`
+- Added ETag-based HTTP 304 Not Modified responses for HTML pages in release mode, reducing bandwidth by returning empty body when content hasn't changed ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.7/crates/brk_website/src/handlers.rs))
+- Compute and cache a hash-based ETag for index.html on first request, used for subsequent conditional requests ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.7/crates/brk_website/src/website.rs))
+
+#### `website`
+- Added upper price band (I²/R) and lower price band (R²/I) series to the price comparison chart ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.7/website/scripts/options/distribution/prices.js))
+
+### Bug Fixes
+
+#### `brk_types`
+- Fixed unrealized value calculation in cost basis distribution to compute `(spot - cost_basis) × supply` instead of `spot × supply`, correctly reflecting unrealized profit/loss per bucket ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.7/crates/brk_types/src/cost_basis_distribution.rs))
+- Fixed `Dollars * Sats` multiplication to use `i128` intermediate values, preventing overflow on large values ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.7/crates/brk_types/src/dollars.rs))
+
+### Internal Changes
+
+#### `brk_computer`
+- Moved price rounding logic and unrealized state cache from `CohortState` into `CostBasisData`, encapsulating all cost basis concerns in a single structure ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.7/crates/brk_computer/src/distribution/state/cost_basis/data.rs))
+- Added `compute_unrealized_states()` method on `CostBasisData` that combines cache management and unrealized computation in one call
+- Removed `CachedUnrealizedState` from public API, making it `pub(super)` only
+- Removed `range()` method from `CostBasisData` (unrealized computation now accesses the map directly)
+- Added binary transform constructors (`from_block_last_and_lazy_block_last`, `from_lazy_block_last_and_block_last`, `from_binary`) across height, date, and height-derived lazy metric levels to support mixed computed/lazy binary operations
+
+#### `website`
+- Changed shared time data type from `number[]` to `MetricData` throughout the chart system, propagating stamp metadata alongside data
+- Added `lastTimeStamp` tracking to prevent redundant chart updates when time data hasn't changed
+
+#### `clients`
+- Bumped JavaScript and Python client versions
+
+[View changes](https://github.com/bitcoinresearchkit/brk/compare/v0.1.6...v0.1.7)
+
+## [v0.1.6](https://github.com/bitcoinresearchkit/brk/releases/tag/v0.1.6) - 2026-02-05
+
+### New Features
+
+#### `brk_types`
+- Added `CostBasisDistribution` struct with pco-compressed serialization/deserialization for storing price-to-sats distributions, and a `format()` method supporting bucket aggregation and value type transformation ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.6/crates/brk_types/src/cost_basis_distribution.rs))
+- Added `CostBasisBucket` enum with 7 aggregation strategies: `raw` (no aggregation), `lin200`/`lin500`/`lin1000` (linear buckets by dollar amount), and `log10`/`log50`/`log100` (logarithmic buckets per decade) ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.6/crates/brk_types/src/cost_basis_bucket.rs))
+- Added `CostBasisValue` enum with three output modes: `supply` (BTC at each price), `realized` (USD cost basis), `unrealized` (USD at spot price) ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.6/crates/brk_types/src/cost_basis_value.rs))
+- Added `Cohort`, `CostBasisParams`, `CostBasisCohortParam`, and `CostBasisQuery` types for cost basis API path and query parameters ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.6/crates/brk_types/src/cost_basis_params.rs))
+- Added `round_to()` and `round_to_dollar()` methods on `CentsUnsigned` and `CentsUnsignedCompact` for rounding prices to N significant digits ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.6/crates/brk_types/src/cents_unsigned.rs))
+- Implemented `FromStr` for `Date` type enabling parsing from "YYYY-MM-DD" format ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.6/crates/brk_types/src/date.rs))
+
+#### `brk_computer`
+- Added daily cost basis snapshot writing for all, sth, and lth UTXO cohorts, persisting the merged price-to-sats distribution to disk per date for historical querying ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.6/crates/brk_computer/src/distribution/cohorts/utxo/groups.rs))
+- Added configurable price rounding for cost basis data: UTXO cohorts use 5 significant digits and address cohorts use 4 significant digits, reducing unique price points for more efficient storage and aggregation ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.6/crates/brk_computer/src/distribution/state/cohort/base.rs))
+
+#### `brk_query`
+- Added cost basis query methods: `cost_basis_cohorts()` to list available cohorts, `cost_basis_dates()` to list available dates per cohort, `cost_basis_distribution()` to retrieve raw data, and `cost_basis_formatted()` to get bucketed/value-transformed output ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.6/crates/brk_query/src/impl/cost_basis.rs))
+
+#### `brk_server`
+- Added three new API endpoints for cost basis distribution: `GET /api/metrics/cost-basis` (list cohorts), `GET /api/metrics/cost-basis/{cohort}/dates` (list dates), and `GET /api/metrics/cost-basis/{cohort}/{date}?bucket=&value=` (get distribution data) ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.6/crates/brk_server/src/api/metrics/mod.rs))
+
+#### `brk_client`
+- Added `get_cost_basis_cohorts()`, `get_cost_basis_dates()`, and `get_cost_basis()` methods to the Rust client for querying cost basis distributions ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.6/crates/brk_client/src/lib.rs))
+
+#### `brk_bindgen`
+- Added wildcard (`*`) and `Object` type mapping to `serde_json::Value` in Rust type generation ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.6/crates/brk_bindgen/src/generators/rust/types.rs))
+
+### Bug Fixes
+
+#### `website`
+- Fixed chart range restoration on Safari by wrapping the range-set logic in `requestAnimationFrame` for browser compatibility ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.6/website/scripts/chart/index.js))
+
+### Internal Changes
+
+#### `brk_computer`
+- Reorganized cost basis state storage: height-based snapshots now stored under `by_height/` subdirectory, renamed `cost_basis_data` module to `data`
+- Moved pco compression dependency from `brk_computer` to `brk_types` for reuse across crates
+- Refactored the K-way merge in aggregate percentile computation to collect merged entries with price deduplication during the merge pass
+
+#### `brk_error`
+- Added `pco` feature flag and `Pco` error variant for pco compression errors ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.6/crates/brk_error/src/lib.rs))
+
+#### `workspace`
+- Added `*.csv` to `.gitignore`
+
+#### `clients`
+- Bumped JavaScript and Python client versions
+
+[View changes](https://github.com/bitcoinresearchkit/brk/compare/v0.1.5...v0.1.6)
+
+## [v0.1.5](https://github.com/bitcoinresearchkit/brk/releases/tag/v0.1.5) - 2026-02-05
+
+### New Features
+
+#### `website`
+- Added in-memory data cache for chart metric and time data, enabling instant visual feedback when switching between chart indexes without re-fetching from the server ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.5/website/scripts/chart/index.js))
+- Implemented cache-first loading strategy: cached data is rendered immediately while fresh data is fetched in the background, making index switching feel instantaneous
+
+### Bug Fixes
+
+#### `website`
+- Fixed URL range being overwritten during chart initialization by adding an `initialLoadComplete` guard that prevents range persistence until the first data load completes, and resets on rebuild ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.5/website/scripts/chart/index.js))
+- Fixed temporal dead zone (TDZ) error by moving zoom handler registration (`onZoomChange.add`) to after series creation instead of before it ([source](https://github.com/bitcoinresearchkit/brk/blob/v0.1.5/website/scripts/chart/index.js))
+
+### Internal Changes
+
+#### `website`
+- Simplified showLine visibility calculation to use the already-tracked `visibleBarsCount` variable instead of re-reading the visible logical range from the chart
+
+#### `clients`
+- Bumped JavaScript and Python client versions
+
+[View changes](https://github.com/bitcoinresearchkit/brk/compare/v0.1.4...v0.1.5)
+
## [v0.1.4](https://github.com/bitcoinresearchkit/brk/releases/tag/v0.1.4) - 2026-02-04
### Breaking Changes
diff --git a/modules/brk-client/index.js b/modules/brk-client/index.js
index 96e6c50b6..93d20688c 100644
--- a/modules/brk-client/index.js
+++ b/modules/brk-client/index.js
@@ -5005,7 +5005,7 @@ function createRatioPattern2(client, acc) {
* @extends BrkClientBase
*/
class BrkClient extends BrkClientBase {
- VERSION = "v0.1.7";
+ VERSION = "v0.1.9";
INDEXES = /** @type {const} */ ([
"dateindex",
diff --git a/modules/brk-client/package.json b/modules/brk-client/package.json
index f47f2d9ae..f5447d19f 100644
--- a/modules/brk-client/package.json
+++ b/modules/brk-client/package.json
@@ -34,5 +34,5 @@
"url": "git+https://github.com/bitcoinresearchkit/brk.git"
},
"type": "module",
- "version": "0.1.7"
+ "version": "0.1.9"
}
diff --git a/packages/brk_client/brk_client/__init__.py b/packages/brk_client/brk_client/__init__.py
index 47b43b31d..18522278d 100644
--- a/packages/brk_client/brk_client/__init__.py
+++ b/packages/brk_client/brk_client/__init__.py
@@ -4423,7 +4423,7 @@ class MetricsTree:
class BrkClient(BrkClientBase):
"""Main BRK client with metrics tree and API methods."""
- VERSION = "v0.1.7"
+ VERSION = "v0.1.9"
INDEXES = [
"dateindex",
diff --git a/packages/brk_client/pyproject.toml b/packages/brk_client/pyproject.toml
index bba2798de..c0c1e9274 100644
--- a/packages/brk_client/pyproject.toml
+++ b/packages/brk_client/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "brk-client"
-version = "0.1.7"
+version = "0.1.9"
description = "Python client for the Bitcoin Research Kit"
readme = "README.md"
requires-python = ">=3.9"