# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.7.0] — 2026-05-20
### Changed
- **Breaking:** Bump `dds-bridge` to **0.19** and `dds-bridge-sys` to **3.0**
(the latter is a dev-dependency used only by `tests/solver.rs`). The
underlying DDS C++ library moves to v3.0.0 with PascalCase struct names
and snake_case fields; `pons`'s own safe API is unaffected, but downstream
users who pin to older versions of these dependencies should also bump
them in lockstep. See the `dds-bridge-sys` v3.0.0 and `dds-bridge` v0.19.0
changelogs for the rename map.
### Added
- New `defend-2sx-or-3nt` example: compares the expected NS score from
defending 2♠× vs declaring 3NT after the auction `(2♠) X (P)`. The
bidding system is a single `Trie` with three classifiers — West's
weak-two opening at `[]`, North's takeout double at `[2♠]`, and South's
natural call at `[2♠, X, P]` (which may be Pass, 3NT, or an
out-of-scope call such as a 3-level new suit, jump in hearts, or
Lebensohl 2NT). South's classifier is used only as an eligibility
filter: deals are rejection-sampled so only those where West opens 2♠,
North doubles, *and* South naturally faces a P-or-3NT decision are
kept and double-dummy solved. Each accepted deal is scored under three
strategies — always defend 2♠×, always declare 3NT, and a per-deal
oracle that picks the higher of the two — giving an upper bound on
what any policy keyed on South's hand could achieve. Scoring uses
`dds_bridge::Contract::score`. Accepts an optional `--south` for
hand-specific analysis (errors if the hand falls out of scope) or
randomizes all four seats when omitted.
## [0.6.1] — 2026-04-25
### Changed
- Updated `dds-bridge` dependency to 0.18
- `full_deal` now returns `FullDeal` (was `Deal`)
- `fill_deals` now takes a pre-validated `PartialDeal`; no longer returns `Result`
- Track `dds-bridge`'s trick-count rename: `solver::TricksTable` → `solver::TrickCountTable` in `stats::HistogramTable`'s `FromIterator` impl and in the `check-zar` / `check-nltc` examples. Pure rename on the consumer side.
- The `serde` feature now also pulls in `serde_with` (optional dep).
### Internal
- Replaced the last hand-written `serde_impl` submodule (on `Deck`) with `serde_with::SerializeDisplay` / `DeserializeFromStr` derives. No change to the serialized form.
- Replaced non-const `.unwrap()` in tests and the `Auction::declarer` doctest with `?` propagation. Tests with a single fallible error type return `Result<(), E>`; tests mixing error types or unwrapping `Option` return `anyhow::Result<()>`.
- Moved inline `mod tests` blocks in `bidding.rs` and `deck.rs` into dedicated `bidding/tests.rs` and `deck/tests.rs` files. No behavior change.
## [0.6.0] — 2026-04-19
### Added
- Optional `serde` feature for serialization/deserialization support
- `Display` and `FromStr` implementations for `Deck` and bidding types
- `Classifier` promoted to a trait (was a plain `fn` in 0.5.0)
- Constructors for `Forest`
- `FusedIterator` implementation for `Trie` iterators
- `Debug` on `Trie` and iterator types
- Slicing API for `Auction`; `Index<Range<Bid>>` and bid-range indexing on `Array`
- `Logits::softmax` (replaces `to_odds`); returns `None` when all logits are `-∞`
- `fill_deals` helper
- Criterion benchmarks for shuffle, trie, and parallel solving
- proptest-based roundtrip and histogram invariant tests
### Changed
- `System::classify` now takes a slice
- `Auction::push` is panicking; confusing `force_push` removed
- `Deck` rejects duplicate cards
- `RelativeVulnerability` renamed from previous type
- Converters borrow instead of consuming
- Public fields replaced with getters
- Error types marked `#[non_exhaustive]`
- `average_ns_par` return type improved; redundant count parameter removed
- Random deal generation moved to `dds-bridge`; local `solver` module renamed to `random`
- Deterministic stats moved to `mod stats`
- MSRV pinned to 1.93
- Updated `dds-bridge` dependency to 0.16
### Fixed
- Memory leak in `Array::try_map`
- `hcp_plus` calculation
### Internal
- Added `#[inline]` to trivial getters on `Copy` types
- Aligned `HistogramRow::count` to take `self` (non-breaking: `HistogramRow: Copy`)
- Deduplicated `Map::get_mut`
- Bidding context lives with the stored classifier; shared API between systems and classifiers
- Hardened GitHub workflow; CI enforces `fmt`, `clippy`, and doc warnings
- Expanded README; documented the `map` module
## [0.5.0] — 2026-03-25
### Added
- `Array<T>` modeling `Call -> T`, with `Array`-like and full iterator API
- `Map` with iteration over keys, values, and entries; separated iteration for arrays
- `Logits` module (under `mod array`); `Logits::to_odds`
- Abstract bidding table supporting multiple calls per node
- Classifier concept (as a plain `fn`) replacing the filter-based approach
- Own `bidding::Vulnerability` type
- Absolute `bidding::Frequency` for easier filtering
- Different indices for X (double) and XX (redouble)
### Changed
- Edition updated to Rust 2024
- Magic number 38 replaced with a named constant
## [0.3.1] — 2025-05-31
### Fixed
- `Strategy` now requires `RefUnwindSafe` so `Trie` stays `UnwindSafe`
### Internal
- Inlined small functions for optimization
## [0.3.0] — 2025-05-30
### Added
- Core bridge data structures: `Card`, `Suit`, `Hand`, `Deck`, `Holding`
- `SmallSet` trait for `Holding` and `Hand`
- DDS (double-dummy solver) integration via `dds-bridge`
- Contract scoring
- Bitset operators for `Holding` and `Hand`
- Basic CLI to solve random deals
- Hand evaluation (LTC, NLTC, BUM-RAP, Zar points)
- `Auction` with `push`, `pop`, and `truncate`
- `Trie` for bidding strategies, with depth-first iteration, suffix and prefix iterators
- Statistics utilities for evaluators; histograms
[0.7.0]: https://github.com/jdh8/pons/compare/0.6.1...0.7.0
[0.6.1]: https://github.com/jdh8/pons/compare/0.6.0...0.6.1
[0.6.0]: https://github.com/jdh8/pons/releases/tag/0.6.0
[0.5.0]: https://github.com/jdh8/pons/releases/tag/0.5.0
[0.3.1]: https://github.com/jdh8/pons/releases/tag/0.3.1
[0.3.0]: https://github.com/jdh8/pons/releases/tag/0.3.0