Skip to content

audit: remediate all 106 findings from the July 2026 ecosystem audit - #9

Merged
alexnodeland merged 32 commits into
mainfrom
audit/2026-07-remediation
Jul 13, 2026
Merged

audit: remediate all 106 findings from the July 2026 ecosystem audit#9
alexnodeland merged 32 commits into
mainfrom
audit/2026-07-remediation

Conversation

@alexnodeland

Copy link
Copy Markdown
Owner

Summary

Remediates all 106 findings (EV-01…EV-106) from the July 2026 fugue-ecosystem audit — mathematical soundness, correctness, performance, API design, docs, and packaging. No deferrals: every finding carries a final resolution in AUDIT-2026-07.md, and every fix was independently re-verified by an adversarial review pass (106/106 verified).

Highlights:

  • CMA-ES: correct eigendecomposition-based sampling/update path (nalgebra SymmetricEigen), fixed step-size adaptation and rank-μ update math (EV-01, EV-05, EV-24, …)
  • NSGA-II: crowding-distance and non-dominated-sort corrections (EV-10…EV-15, …)
  • Hyperparameter tuning: replaced the fake "Bayesian" hyperparameter learner with an honest Thompson-sampling tuner (EV-21…EV-23, …)
  • Checkpointing: ChaCha RNG state round-trips exactly; added a resume API with determinism regression tests (EV-02, EV-45…EV-48, …)
  • Reproducibility: two-pass variance in compute_rhat, splitmix64 island-seed derivation, seed property tests (EV-106 + re-verification fixups)
  • Packaging/CI: depend on sibling fugue-ppl via path + version (EV-30); CI clones the sibling fugue repo (same-named branch when it exists, else main)

Full finding-by-finding log: AUDIT-2026-07.md (each entry has a resolution, regression tests, and an independent re-verification verdict).

Test plan

  • cargo test — 706 tests green against sibling fugue (post-remediation)
  • cargo clippy clean, cargo fmt --check clean
  • Post-remediation regression review over the full diff (5 module-cluster reviewers); all surfaced issues fixed in the fixup commits

Note: CI resolves the fugue-ppl path dependency by cloning alexnodeland/fugue. Until fugue PR #36 merges, the clone step uses fugue's matching audit/2026-07-remediation branch; after #36 merges it falls back to main automatically.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2

alexnodeland and others added 30 commits July 10, 2026 21:21
EV-07: Individual::set_fitness now panics on NaN (documented invariant);
best()/worst()/sort_by_fitness() are NaN-safe via a total order that ranks
NaN strictly worst.
EV-08: best()/worst()/sort_by_fitness() delegate to FitnessValue::is_better_than()
(new cmp_by_quality helper) instead of a to_f64() scalar, fixing wrong results
for ParetoFitness with infinite crowding distances.
EV-13: NSGA-II crowding distance for parent selection is recomputed per
non-dominated front (Deb 2002) via recompute_crowding_distance_per_front,
replacing the whole-population computation in step/step_bounded/run/run_bounded.
EV-28: genome_mut() and new set_genome() clear the cached fitness/evaluated flag.
EV-84: binary tournament draws two distinct competitors (sample without replacement).
EV-85: closure MultiObjectiveFitness replaced by ClosureMultiObjective wrapper
with an explicit objective count instead of hardcoded 2.

Regression tests added for each finding.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
EV-27: SubtreeMutation now derives its replacement-subtree depth budget from
max_depth - depth(mutation point) and accounts for generate_grow's +1 growth,
so the genome max_depth invariant is preserved (with a terminal fallback guard).

EV-71: bounded SBX now uses Deb & Agrawal's bounds-aware spread factor (truncated
beta_l/beta_u per gene) so children land inside [min,max] by construction with no
boundary probability atom, replacing the old clamp-only path.

EV-72: split the conflated probability into per-pair crossover_probability
(default 0.9, reported by the trait) and per-gene exchange_probability
(default 0.5, canonical), with distinct fields, builders, and docs.

EV-101: hand-written Default for SwapMutation/PermutationSwapMutation/InsertMutation
delegates to new() (count = 1) instead of the derived count = 0 no-op.

EV-102: unbounded PolynomialMutation applies a local Gaussian perturbation
(sigma default 0.1*(1+|x|), configurable) instead of fabricating +/-1e10 bounds.

EV-103: MutationOperator::mutation_probability now returns Option<f64>, reporting
None for the length-dependent 1/n default rather than a false 1.0.

EV-104: TournamentSelection samples with replacement by default (canonical);
without_replacement() retains the distinct-competitor variant; determinism docs fixed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
…EV-62, EV-97

CMA-ES (cmaes.rs):
- EV-01: replace the broken hand-rolled cyclic-Jacobi routine (which never
  mutated its input and returned wrong/negative eigenvalues) with
  nalgebra::SymmetricEigen. Add eigenpair/positivity/reconstruction tests plus
  a seeded 5-D Rosenbrock convergence test.
- EV-36: evaluate the bound-repaired (feasible) point but adapt the
  distribution (m/C/paths/sigma) from the UNREPAIRED sample; add an optional
  quadratic boundary penalty. Best-solution tracking moved to step() and reports
  the feasible point.
- EV-37: recompute the eigensystem on the correct per-generation cadence
  max(1, floor(1/(10 n (c1+cmu)))) instead of a factor-of-lambda too infrequent.
- EV-38: replace the trace-only eigendecomposition test with real
  eigenvalue/eigenvector/reconstruction assertions.

Self-adaptive ES (self_adaptive.rs):
- EV-05/EV-24: swap the log-normal learning rates so the shared once-per-
  individual deviate carries tau'=1/sqrt(2n) and per-coordinate deviates carry
  tau=1/sqrt(2 sqrt n) (Beyer & Schwefel); fix LearningRates::for_dimension and docs.
- EV-97: isotropic case uses tau0 = 1/sqrt(n).
- EV-62: rename the 1e-10 constant to SIGMA_UNDERFLOW_FLOOR (honest doc) and add
  a configurable, problem-scaled min_sigma (default 1e-8*initial_sigma).

Evolution Strategy (evolution_strategy.rs):
- EV-40: default self-adaptive ES now uses (mu,lambda) comma selection; plus
  remains an explicit option; docs explain why elitism suppresses sigma
  self-adaptation. Thread the configurable min_sigma through the mutation path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
Redesign the operator-parameter learner as an honest Thompson-sampling
bandit and wire it into SimpleGA; fix the Gamma/Beta/log-moment estimators;
add turbofish-free builder entry points and build-time config validation.

- EV-23/EV-21: ThompsonSamplingTuner — each tunable parameter is discretized
  into arms, each arm holds a Beta posterior over P(improve | arm); Thompson
  arm-selection applies the arm VALUE (never the Beta draw). Wired into
  SimpleGA via .adaptive_operators(ThompsonConfig) + run_adaptive(); example
  and integration test exercise the real loop and assert feedback flows.
- EV-22: GammaPosterior is an honest rate posterior; adds
  posterior_mean_of_mean() = beta/(alpha-1); eta params no longer shoehorned
  into an exponential likelihood.
- EV-61: LogNormalPosterior -> RunningLogMoments; Welford variance with no
  small-n prior contamination.
- EV-95: BetaPosterior::observations() = (alpha-alpha0)+(beta-beta0).
- EV-96: PolynomialDecay doc formula corrected to match the implementation.
- EV-35: SimpleGABuilder::real_valued()/bit_string()/permutation() — zero
  turbofish; sphere_optimization example updated + negation comment fixed.
- EV-86: build() validates population/elite/crossover-prob/bounds with typed
  Configuration errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
…V-66, EV-67, EV-68, EV-69, EV-70, EV-98, EV-99, EV-100

Bradley-Terry (bradley_terry.rs):
- EV-06: recompute_all() is now driven from process_pairwise so the live loop re-fits the MLE.
- EV-67: genuine Gaussian log-strength prior (NR) + Gamma pseudo-count prior (MM) keep all-win/all-loss finite.
- EV-25/EV-66: strength-scale covariance via delta method from the sum-to-zero-constrained Fisher pseudo-inverse (ridge hack dropped); NR and MM now report Var(pi) on the same scale.
- EV-65: Armijo sufficient-INCREASE condition (sign fixed) with a testable backtracking line search.

Aggregation (aggregation.rs):
- EV-06: process_pairwise re-fits Bradley-Terry before returning fitness.
- EV-98: ImplicitRanking variance propagated to the score scale; Elo variance given a positive steady-state floor.

Selection (selection_strategy.rs):
- EV-68: find_informative_pair excludes the already-chosen index (no self-pairs).
- EV-69: exploration/coverage bonuses normalized by mean population variance (model-agnostic).
- EV-70: zero-variance/known pairs score ~0 (not max); only truly unobserved pairs get the max sentinel.
- EV-99: entropy consistently in nats; sentinel = ln(2).
- EV-100: softmax inverse-CDF fallback picks the last index, not index 0.

Session/algorithm (session.rs, algorithm.rs):
- EV-26/EV-64: update_fitness* are pure setters; evaluation_count is owned solely by the presented-id loop (exactly once per response, symmetric in pairwise).
- EV-63: elites keep their CandidateId (and history) across generations.

Adds regression tests for every finding (lib + tests/e-interactive_audit.rs).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
…58, EV-59, EV-60, EV-91, EV-92, EV-93, EV-94

Genome-layer audit remediation:

- EV-03: CompositeGenome trace round-trip now delegates to each component's
  own to_trace/from_trace, namespacing entries under "first/"/"second/" —
  no hardcoded encoding prefixes. Works for Permutation/Tree components.
- EV-04: TreeGenome trace encode/decode is now lossless (function -> index in
  the stable F::functions(); terminal -> (discriminant, payload) via new
  Terminal::encode/decode). from_trace(to_trace(g)) reproduces g exactly.
- EV-19/EV-20/EV-55: distance() panics on structural mismatch (was silent
  0.0 / truncation); added try_distance() -> Result on the trait and per type.
- EV-56: added Bounds::try_new (rejects min > max); normalize()/denormalize()
  handle degenerate min==max (0.5 / min) instead of dividing by zero.
- EV-57: added length-aware variation operators for DynamicRealVector in
  src/genome/dynamic_ops.rs (cut_and_splice + DynamicGaussianMutation).
- EV-58: DynamicRealVector::generate no longer panics on empty bounds; added
  try_generate() -> Result for the degenerate case.
- EV-59: RealVector/BitString/Permutation from_trace distinguish MissingAddress
  (stop) from a present-but-wrong-typed choice (TypeMismatch error).
- EV-60: iterative eval/depth/size + explicit iterative teardown for deep
  trees (a Drop impl is impossible — E0509 in the un-owned operator layer).
- EV-91: DynamicRealVector to_trace/from_trace derive the gene address from
  trace_prefix() so it cannot diverge.
- EV-92: renamed new_unchecked -> from_vec_unchecked with documented invariants
  and a debug_assert!(is_valid).
- EV-93: EvolutionaryGenome::distance is now a required trait method.
- EV-94: documented the MultiBounds-as-length convention on generate() and
  added honest per-type constructors (generate_with_len / generate_with_depth).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
…, EV-90

Make the fugue_integration layer a genuine "evolution as Bayesian inference"
pipeline over the Boltzmann posterior pi_beta(x) ∝ p(x)·exp(beta·f(x)).

- EV-16: EvolutionarySMC is now a valid tempered SMC sampler — incremental
  importance weights w_t = exp((beta_t - beta_{t-1})·f(x)) from the pre-move
  state, accumulated across non-resampling steps, self-normalised, ESS-triggered
  systematic resampling with weights reset to uniform, and pi_beta-invariant MH
  mutation/crossover rejuvenation. Regression test matches the analytic Gaussian
  conjugate posterior.
- EV-52: to_weighted_trace runs a real fugue `factor(beta·f)` model through the
  new TraceScoringHandler so total_log_weight() == beta·f(x) (log_factors), not 0.
- EV-51: effect handlers rewritten on fugue's real Handler contract
  (TraceScoringHandler, RecordingHandler with correct log-weight bookkeeping);
  the ad-hoc "Poutine handlers" are honestly renamed to operation hooks and the
  stale/zero per-choice logp is no longer fabricated.
- EV-90: EvolutionStep MH acceptance uses the full target incl. the prior, so
  out-of-bounds proposals are rejected; stationary law is the on-bounds Boltzmann
  posterior (test: no escape + mean matches truncated-exponential).
- EV-53: HBGA replaced by BayesianAdaptiveGA — conjugate Beta/Gamma posteriors
  over per-operator success probability + improvement rate, Thompson sampling
  each generation (renamed honestly: single-level, not "hierarchical").
- EV-54: gaussian_mutation / bounded_mutation use rand_distr::Normal(0, sigma)
  so the perturbation std is exactly sigma (test on sample std).
- EV-17/EV-18: examples/bayesian_evolution.rs runs a genuine end-to-end pipeline
  through the layer (fugue Model/Handler/factor); module docs state the exact
  math; integration tests in tests/e_integration_bayesian.rs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
… EV-44 EV-49 EV-50 EV-73 EV-79 EV-80 EV-81 EV-82 EV-83 EV-88 EV-105

Island model (island.rs):
- EV-12 persistent per-island StdRng seeded once from the master RNG -> seeded
  runs are bit-reproducible even with parallel island evaluation.
- EV-11 FullyConnected/Star migration broadcasts to ALL topology targets.
- EV-41 immigrants replace the island's worst members, never the best.
- EV-82 evaluation counter counts only newly-evaluated individuals.
- EV-83 saturating elite arithmetic (no usize underflow for large elitism).

Steady-state (steady_state.rs):
- EV-43 generate/evaluate exactly offspring_count children.
- EV-42 ReplaceRandom/ReplaceWorst/TournamentWorst replace unconditionally;
  new ReplaceIfBetter is the elitist accept-if-better option.
- EV-44 optional prevent_duplicates(bool) genome de-duplication (O(n)).

UMDA (eda/umda.rs):
- EV-39 rejection sampling from the truncated region (retry 100 then clamp).
- EV-81 Bessel (n-1) sample variance.
- EV-80 selection uses is_better_than, not to_f64.
- EV-79 builder validates ranges in build() (Result) instead of clamping.
- EV-10 tests: seeded UMDA beats a same-budget random-search baseline and the
  learned model converges to the optimum (via new run_with_model).

Convergence (diagnostics/convergence.rs):
- EV-14 evolutionary_rhat truncates chains to the common minimum length.
- EV-49 target-fitness check reads the tracked running best.
- EV-50 Stagnation criterion honors its configured threshold.
- EV-88 R-hat uses incremental prefix-sum statistics (no full-history rescan).

Termination (termination/mod.rs):
- EV-73/EV-105 FitnessStagnation uses best-so-far window improvement.

Benchmarks (fitness/benchmarks.rs):
- EV-15 DixonPrice::optimal_solution() uses the canonical 1-based exponent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
…icy regression suite

- tests/property_tests.rs: replace rand::thread_rng() with StdRng seeded from
  a proptest-generated any::<u64>() input in all 10 RNG-driven proptests, so
  failures reproduce byte-for-byte via proptest's own seed/shrink file instead
  of drawing fresh entropy on every re-run.
- tests/e_tests_seeded_determinism.rs (new): for SimpleGA, CMA-ES, (mu+lambda)-ES,
  UMDA, and NSGA-II, assert two runs with the same StdRng seed produce an
  identical best genome/fitness (or final population), and two runs with
  different seeds (almost surely) differ.
- tests/e_tests_nan_policy.rs (new): assert Population::evaluate, SimpleGA::run,
  EvolutionStrategy::run, and ContinuousUMDA::run all panic with a documented
  message when a fitness function returns NaN, per the EV-07 wave-A policy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
- EV-02: real RNG round-tripping. Add rand_chacha (serde1) and a SnapshotRng
  trait (ChaCha8/12/20Rng) with capture()/restore(); Checkpoint::with_rng /
  restore_rng thread it through. Rewrite examples/checkpointing.rs to prove
  bit-identical resume (20 straight vs 10 + disk checkpoint + restore + 10);
  add integration test tests/e-checkpoint_resume.rs.
- EV-45: version compatibility now checked uniformly (JSON, binary, compressed);
  VersionTooOld is actually returned for pre-minimum schemas.
- EV-46: CheckpointManager scans existing files on construction and continues
  the index after the max found (restart-safe).
- EV-47: atomic writes - serialize to <path>.tmp, fsync, then fs::rename.
- EV-48: configurable bincode size limit (default 256 MiB); oversized files and
  corrupt length prefixes return a typed TooLarge error.
- EV-87: checkpoint indices zero-padded to 8 digits; load_latest orders by
  parsed numeric index (backward-compatible with legacy names).
- EV-89: checkpoint (de)serialization errors preserve the source chain via
  #[source] (new SerializeError/DeserializeError variants).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
- EV-09: install console_error_panic_hook in the wasm_bindgen(start) init so
  Rust panics log real file/line instead of an opaque `unreachable` trap;
  document panic semantics. JS-boundary audit: no panicking unwraps remain
  (fitness helpers use saturating unwrap_or fallbacks).
- EV-32: route every fallible EvolutionError boundary through
  evolution_error_to_js so JS receives structured {type, message} errors;
  the previously-dead function is now live.
- EV-33: report the REAL NSGA-II evaluation count via a counting fitness
  decorator (CountingMoFitness); delete the fabricated pop*gens*2 formula.
- EV-34: add a native incremental stepping API to SimpleGA
  (init_run/step_generation/finish_run) and refactor run() to drive it
  (behavior identical); expose a SteppedRealOptimizer in wasm with
  step(n)/progress getters/early cancel.
- EV-75: remove unused serde-wasm-bindgen and wasm-bindgen-futures deps.
- EV-76: CMA-ES fitness_history now records per-generation best-so-far by
  driving step() directly, instead of a single flat point.
- EV-77: add an IslandModelOptimizer wasm binding (Ring/FullyConnected/Star
  topologies, best-k migration) built on the step API plus new migration
  helpers (SimpleGaRun::best_genomes / SimpleGA::inject_migrants); the native
  island module is unavailable in wasm (requires the parallel/rayon feature).
- Tests: native step/migration equivalence tests; host regression tests
  (e_wasm_regressions.rs) plus browser wasm_bindgen tests covering the step
  API, island model, CMA-ES history, real NSGA-II count, and structured errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
…9, EV-30, EV-31, EV-74, EV-78)

- EV-29: reconcile license metadata to a single MIT license (matching
  fugue-ppl) in fugue-evo/Cargo.toml and crates/fugue-evo-wasm/Cargo.toml;
  add a root LICENSE (MIT text, copyright Alex Nodeland 2025-2026); update
  both READMEs off the unsupported "MIT OR Apache-2.0" claim (no
  LICENSE-APACHE/LICENSE-MIT texts ever existed for that claim).
- EV-30: verified a `path = "../fugue", version = "0.1.0"` dependency
  compiles cleanly against the current sibling checkout (cargo check
  --all-targets, cargo test --lib: 645 passed) -- but the sibling `fugue`
  repo is independently, concurrently under its own active audit
  remediation and was observed to go from green to red minutes later from
  unrelated in-progress edits with zero change on the fugue-evo side. A
  hard path dependency makes fugue-evo's own build only as stable as
  fugue's current, possibly-mid-edit working tree, which is exactly the
  fragility a crate published independently to crates.io should not have.
  Kept `fugue-ppl = "0.1.0"` pinned to the registry release instead, and
  documented (with a verified-working example) how to opt into the sibling
  via a local, uncommitted `[patch.crates-io]` override in README.md's new
  Development section.
- EV-31: move crates/fugue-evo-wasm's [profile.release] (opt-level "s", LTO)
  to the workspace-root Cargo.toml, where cargo actually honors it; the
  member manifest keeps a comment pointing at the root.
- EV-74: proptest unconditionally pulls in rand 0.9/rand_core 0.9/rand_chacha
  0.9 alongside our own rand 0.8 stack; confirmed via `cargo tree -i` that
  this holds even pinned to proptest 1.7.0 and that the upstream fugue
  sibling has the identical duplication despite the same proptest = "1.0"
  pin. Documented as upstream-forced in Cargo.toml rather than "fixed" by a
  version bump.
- EV-78: reworded the misleading "we negate because fugue-evo maximizes"
  comment in examples/sphere_optimization.rs (Sphere already negates
  internally) and fixed the printed "Best fitness" to un-negate the sum of
  squares so it reads as the expected near-zero, non-negative optimum;
  scanned other examples for the same pattern (none found; the one other
  "negate" comment, in symbolic_regression.rs, describes a genuine
  user-authored negation and is accurate as-is).
- README/SPEC surgical updates: Bayesian hyperparameter learning is a wired,
  opt-in ThompsonSamplingTuner; the Fugue integration runs a genuine
  tempered-SMC/Boltzmann pipeline with a flagship bayesian_evolution.rs
  example; checkpointing supports bit-identical resume for the ChaCha RNG
  family. SPEC.md gets a dated implementation-note callout rather than a
  rewrite.
- CHANGELOG.md: added an Unreleased section summarizing the full 2026-07
  audit remediation (EV-01 through EV-106).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
Fixes the re-verification items flagged after the 2026-07 remediation:

- EV-02: add a library-level checkpoint resume path — SimpleGA::checkpoint_run
  / resume / run_from_checkpoint thread a SnapshotRng (ChaCha) through the run
  loop for bit-identical resume; un-gate the incremental stepping API for all
  builds; rewrite examples/checkpointing.rs to use it; add regression tests.
- EV-04: add Pow to ArithmeticFunction::functions() (and protect Pow against
  NaN) so every function variant round-trips losslessly; harden encode_function
  with a debug_assert; add per-variant and Pow round-trip regression tests.
- EV-17: correct the crate-level framing in lib.rs/README.md/SPEC.md so the
  "evolution as Bayesian inference" headline scopes to fugue_integration and the
  default algorithms are described as standalone EC using Trace as a container.
- EV-21: document schedules.rs and adaptive.rs as unintegrated building blocks
  (hyperparameter/mod.rs + module docs), matching the Beta/Gamma treatment.
- EV-34: add per-generation progress/cancel callbacks to all remaining WASM
  optimizers (BitString/Permutation/Nsga2/SymbolicRegression via the step API;
  ES/UMDA via new native run_with_callback hooks); add tests.
- EV-35: replace the 7-param turbofish quickstart with SimpleGABuilder::real_valued()
  in README, lib.rs, examples, and docs.
- EV-60: add a stack-safe Drop for TreeNode (mem::take teardown), make the
  position collectors and PointMutation iterative; add 100k-deep drop/positions/
  mutation regression tests.
- EV-74: pin proptest = ">=1.5, <1.7" to collapse the duplicate rand major;
  add a `make deps-check` (cargo tree -d) CI guard; correct the Cargo.toml/
  CHANGELOG notes.
- EV-83: add an island regression test for elitism > population size.
- REG-1: track a pure running max (separate from the stagnation-throttled best)
  so target-fitness detection is not missed when stagnation_threshold > tolerance.
- REG-2: correct the CHANGELOG EV-30 entry to match the actual crates.io
  dependency and the README's documented rationale.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
…n (re-verification lows)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
…low-up)

Flip fugue-ppl from the published crates.io release to the co-developed
sibling checkout via `path = "../fugue"` (version = "0.1.0" retained), so
fugue-evo's Fugue integration is finally exercised against the actual
co-developed source now that fugue's 2026-07 audit remediation has landed
with a green full-test gate.

Adapt genome::composite trace namespacing to fugue's new Address struct
(Address::new(..)/addr.as_str() replacing the former tuple-struct Address(..)
constructor and .0 field); no behavior change. Reconcile the now-stale EV-30
CHANGELOG entry and README "Development" section, which previously documented
the deliberate crates.io pin.

Full suite green: 706 unit/integration tests + 3 doctests pass;
bayesian_evolution example runs end-to-end; wasm crate cargo check clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
…diation complete)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEAKcbnLVP8iSXub2Pqor2
Copilot AI review requested due to automatic review settings July 12, 2026 01:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of lines (20,000). Try reducing the number of changed lines and requesting a review from Copilot again.

@alexnodeland
alexnodeland merged commit de16cda into main Jul 13, 2026
8 checks passed
@alexnodeland
alexnodeland deleted the audit/2026-07-remediation branch July 13, 2026 13:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants