diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 89a1c51..5abc488 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -11,7 +11,7 @@ body:
id: version
attributes:
label: Unsga3 version / commit
- placeholder: "0.1.4 or git SHA"
+ placeholder: "0.1.5 or git SHA"
validations:
required: true
- type: textarea
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 924adf2..9336703 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,16 +14,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
### Changed
- Docs and XML comments describe `initialPopulation` and hybrid loops in generic terms (domain-adapter warm-start / grid-seed). No product-repo names.
+
+## [0.1.5] — 2026-09-22
+
+Forensic-audit wave (G1–G10): document known gaps against pymoo and Seada & Deb, and lock them with tests. The published 15-seed table is not rewritten. **Default tournament stays `RankNicheDistance`.**
+
+### Added
+
+- `ReferenceDirectionThinning.OnePerDirection` as a cardinality aid when comparing a full non-dominated front to a one-per-direction set. It is not a claim that the thinned set matches pymoo `res.F`.
+
+### Fixed
+
+- Duplicate elimination no longer spins when mutation cannot change the decision vector. The key is `G12` significant digits, not 12 decimal places. After the attempt cap, remaining offspring slots may be duplicates.
+- Euclidean distance rejects a shorter vector instead of ignoring the extra coordinates. `ParetoFronts.Zdt1(1)` (and the other single-point samplers) throw. IGD+ has a hand-case test. ZDT6's 0.280775 floor and ZDT3's 0.1822287280 endpoint are documented and locked.
+- Das–Dennis `Count` uses a checked 64-bit combination and throws when the value does not fit in `int`.
+
+### Changed
+
- DTLZ2 pymoo oracle passes `n_var=12` (k=10) to match `Dtlz2Problem`. The published 15-seed table used pymoo’s default `n_var=10` and is not rewritten. Seed 1 was remeasured at n_var=12.
-- Documented that ZDT IGD compares the C# full non-dominated front with pymoo `res.F`. Added `ReferenceDirectionThinning.OnePerDirection` as a cardinality aid, not a parity claim.
+- Documented that ZDT IGD compares the C# full non-dominated front with pymoo `res.F`.
- Documented the collapsed-nadir fallback (nadir = ideal + 1 when the span stays ≤ 1e-6). pymoo 0.6.2 stops at the worst point in the population. Behavior is unchanged and covered by a unit test.
- Documented that default `RankNicheDistance` is not Seada and Deb Algorithm 2. `PymooCompatible` matches the paper's same-niche split; p_c stays 1.0 (paper experiments use 0.9). The default tournament is unchanged.
- Locked the infeasible-point hyperplane rule with a fixture: feasible (1, 1) beside infeasible (0, 0) sets ideal to (0, 0). The rule is unchanged.
- Documented that mating calls `PrepareForSelection`, which re-associates survivors. pymoo keeps the niche ids from survival. A fixture locks the current ids on a five-point pool.
- Documented that `WithDasDennis(1, 1)` throws because N must be at least 2. Single-objective runs pass an explicit population size. N = 1 is not accepted.
-- Indicator edges: Euclidean distance rejects a shorter vector instead of ignoring the extra coordinates. IGD+ has a hand-case test. `ParetoFronts.Zdt1(1)` (and the other single-point samplers) throw. ZDT6's 0.280775 floor and ZDT3's 0.1822287280 endpoint are documented and locked.
-- Duplicate elimination no longer spins when mutation cannot change the decision vector. The key is `G12` significant digits, not 12 decimal places. After the attempt cap, remaining offspring slots may be duplicates.
-- Equivalence docs no longer say the published Wilcoxon table is within 1–2% of pymoo. The DTLZ2 seed-1 guard is 2× the published mismatched scalar 0.00350, so a regression to about 2.9× fails. Das–Dennis `Count` uses a checked 64-bit combination and throws when the value does not fit in `int`. Two-layer reference directions remain absent.
+- Equivalence docs no longer say the published Wilcoxon table is within 1–2% of pymoo. The DTLZ2 seed-1 guard is 2× the published mismatched scalar 0.00350, so a regression to about 2.9× fails. Two-layer reference directions remain absent.
## [0.1.4] — 2026-09-19
@@ -76,7 +91,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
- Benchmarks: ZDT1–4/6, DTLZ1–4/7, Sphere / Ackley / Rosenbrock
- Metrics: IGD, GD, 2-D HV; self-tests + GitHub Packages publish workflow
-[Unreleased]: https://github.com/AppSprout-dev/Unsga3/compare/v0.1.4...HEAD
+[Unreleased]: https://github.com/AppSprout-dev/Unsga3/compare/v0.1.5...HEAD
+[0.1.5]: https://github.com/AppSprout-dev/Unsga3/compare/v0.1.4...v0.1.5
[0.1.4]: https://github.com/AppSprout-dev/Unsga3/compare/v0.1.3...v0.1.4
[0.1.3]: https://github.com/AppSprout-dev/Unsga3/compare/v0.1.2...v0.1.3
[0.1.2]: https://github.com/AppSprout-dev/Unsga3/compare/v0.1.1...v0.1.2
diff --git a/CITATION.cff b/CITATION.cff
index 8f72c6d..8f25156 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -21,8 +21,8 @@ keywords:
- C#
- .NET
license: MIT
-version: 0.1.4
-date-released: "2026-09-19"
+version: 0.1.5
+date-released: "2026-09-22"
references:
- type: article
authors:
diff --git a/Directory.Build.props b/Directory.Build.props
index dd1aa22..2341206 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -12,7 +12,7 @@
https://github.com/AppSprout-dev/Unsga3
https://github.com/AppSprout-dev/Unsga3
optimization;nsga;nsga3;unsga3;multi-objective;evolutionary;moea
- 0.1.4
+ 0.1.5
README.md
diff --git a/README.md b/README.md
index e7b2f3e..50a38c5 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
**U-NSGA-III** (Unified NSGA-III) for .NET — single-, multi-, and many-objective evolutionary optimization with Das–Dennis reference directions, SBX crossover, polynomial mutation, and **niching-based tournament selection** ([Seada & Deb, 2016](https://ieeexplore.ieee.org/document/7271063)).
-> **v0.1.4** — production-usable core with pymoo-aligned normalization. ZDT2 quality protocol is gens=250 (docs/defaults; no algorithm/API change).
+> **v0.1.5** — forensic-audit notes (G1–G10) and small edge fixes. Default tournament stays `RankNicheDistance`. The published 15-seed table is not rewritten. ZDT2 quality protocol remains gens=250.
> **15-seed IGD vs pymoo `UNSGA3`:** ZDT1 **median 0.053 vs 0.070** (MWU *p*≈0.05) compares the full C# non-dominated front with pymoo `res.F`. DTLZ2 **median 0.0045 vs 0.0028** (~1.6×) compares C# n_var=12 with pymoo's default n_var=10. Neither pair is a same-set, same-problem ranking. Notes: [`docs/ORACLE-RESULTS.md`](docs/ORACLE-RESULTS.md).
> Details: [`docs/WILCOXON-RESULTS.md`](docs/WILCOXON-RESULTS.md) · single-seed notes: [`docs/ORACLE-RESULTS.md`](docs/ORACLE-RESULTS.md)