csp-solver 0.4.0

Generic constraint satisfaction problem solver with backtracking, AC-3 constraint propagation, and ordering heuristics.
Documentation
# Changelog

This workspace ships two publishable artifacts across two registries:

- `csp-solver` — the CSP solver crate (crates.io)
- `@mkbabb/csp-solver-wasm` — wasm-pack bindings for `csp-solver` (npm)

**Excised (W11/W12):** `morph-core` (crates.io) and `@mkbabb/morph` (npm) moved
to [`github.com/mkbabb/morph`](https://github.com/mkbabb/morph) at commit
`4568dc7e` (tag `pre-morph-excision`). Their `0.1.0` entries below stay as
historical record — they really did ship from this repo — but everything past
`morph-core 0.1.0` / `@mkbabb/morph 0.1.1` lives in that repo's changelog. The
general-purpose `csp_solver::assignment()` / `AssignmentBuilder` surface morph
was built on stays here; `morph` now consumes it as an ordinary crates.io
dependency (`csp-solver = "0.2"`).

## 0.4.0 — 2026-07-10 (tranche-3, W3 — dead-surface excision)

### npm

- **`@mkbabb/csp-solver-wasm@0.2.0 → 0.4.0`****BREAKING**. The `full-mirror`
  feature and its `isomorphic` module are excised; the published `.d.ts` drops
  `Csp`, `SolveConfig`, `SolveStats`, `OptimizationMode`, `Ordering`,
  `PropagationStrategy`, `Pruning` (the generic py-mirror surface — 7 exports).
  The shipped surface is now the purpose-built `sudoku` + `futoshiki` +
  `assignment` layers only. No in-repo consumer is affected — the frontend
  Worker imports `solveSudoku` / `solveFutoshiki` / `generate*` /
  `solveAssignmentCop` only, never the isomorphic classes; the lean deploy build
  never compiled the isomorphic surface, and its bytes are byte-identical
  pre/post. The `0.4.0` minor bump both encodes the breaking removal across the
  0.x minor slot and aligns the package to the core crate's `0.4.0` surface.

## 0.3.0 — 2026-07-10 (tranche-2, W3 — substrate excision)

### crates.io

- **`csp-solver@0.3.0`** — dead-substrate excision. Breaking (pre-1.0 minor-bump
  class — a `0.2.1` would stay inside the `^0.2` (`>=0.2.0,<0.3.0`) compat range
  and let the crates.io `morph` consumer (`csp-solver = "0.2"`) silently pick up
  the removals; the `0.3.0` minor bump keeps that contract honest):
  - Removed the deferred-driver substrate: `solver/restart.rs` (Luby),
    `solver/heuristic.rs` (conflict-history weighting), `solver/nogoods.rs`
    (`NogoodStore`) and their `solver/mod.rs` `pub mod` lines. The restart /
    nogood / CHS driver was never wired onto the unified kernel; the modules
    were inert public API.
  - `Ordering::Chs` deleted (its only distinction from `Mrv` was the dynamic
    conflict-history weighting that lived in the now-removed `heuristic.rs`;
    weights are frozen at 1.0, so `Chs ≡ Mrv` in behavior).
  - `SolveConfig::restarts` field deleted (accepted-but-inert flag; breaks
    exhaustive struct literals — spread `..Default::default()`).
  - The `SoftConstraint` island removed: the `SoftConstraint` trait,
    `SoftLambdaConstraint` (`constraint/soft.rs`), `ConstraintEnum::Soft`, and
    `Csp::add_soft_constraint`. Branch-and-bound now scores domain costs only.
    `OptimizationMode` / `CostDomain` / `DomainCostEval` are **kept** — bbnf's
    live `MinimizeCost` path draws cost from `CostDomain::cost` via
    `DomainCostEval`, not from soft penalties.
  - `Variable::clear_log` / `Variable::reset_to` deleted (dead restart-driver
    helpers with no remaining caller).
  - Tests: `tests/optimize.rs` trimmed to the `CostDomain` cases;
    `tests/nogoods.rs` and `tests/restart_nogood_soundness.rs` deleted.

## 0.2.0 — 2026-07-06 (grand-uplift tranche, W1–W12)

### crates.io

- **`csp-solver@0.2.0`** — the kernel wave. Breaking (pre-1.0 minor-bump class):
  - `Ordering::DomWdeg``Ordering::Mrv` (the name was a proven misnomer:
    weights frozen at 1.0; `Chs ≡ DomWdeg` bit-for-bit).
  - `SolveConfig::backjumping` deleted (CBJ excised with the unified search
    kernel; breaks exhaustive struct literals — spread `..Default::default()`).
  - `SolveConfig::default()``Ac3` + `FailFirst` (was ForwardChecking +
    Chronological); behavior-visible for default-config consumers.
  - New: unified search kernel (`solver/search.rs`), GAC-in-AllDifferent
    default-ON (Régin, warm-started incremental matching; corpus aggregate
    13.36×, nodes 41,807→5,948), restart/nogood substrate (driver deferred),
    typed `CspError` + `py/` module with 4 typed exceptions, `cancel` +
    `node_budget` + `optimization_mode` on `SolveConfig`, zero-alloc hot path,
    release-guarded `BitsetDomain` 0..128 invariant, Futoshiki generation +
    `FutoshikiPuzzle::from_parts` validation, crate-owned embedded puzzle data
    (`include_dir!`), `AssignmentError::BudgetExceeded`.
  - Excised: `min_conflicts` local search, `CardinalityConstraint`,
    `ConstraintEnum::Lambda` (zero construction sites), CLI-format fixtures.
  - Soundness: the AC-3 `Unsatisfiable` trail-push fix (false-UNSAT 26/113→0/113);
    lattice AC-3 termination fix (default revise honors `prune`'s bool);
    parity matrix 170 rows, 0 completeness violations; solution-set invariance
    + 11 restart/nogood canaries standing guard.

### npm

- **`@mkbabb/csp-solver-wasm@0.2.0`** — split surface: lean sudoku+futoshiki
  deploy artifact (87,853 B raw under `--profile wasm-release
  --no-default-features`) vs the `full-mirror` feature (generic `Csp` mirror,
  `solveAssignmentCop`). Flat-index `Uint32Array` wires with seeded RNG; coded
  errors (`BUDGET_EXCEEDED` vs `UNSAT` distinguishable); `MRV` on the wire;
  vestigial `backjumping` removed; hardened difficulty-parity contract tests.

## 0.1.0 — 2026-05-28 (G.W5 — first publish)

First registry publish of the workspace, landed as part of the muster tranche G
release-engineering wave (G.W5 sub-wave A, CSC411-fold pass).

### crates.io

- **`csp-solver@0.1.0`** — generic constraint satisfaction problem solver: chronological
  backtracking + conflict-directed backjumping, AC-3 + AC-FC propagation, GAC
  all-different (Regin 1994), min-conflicts local search, bitset + finite + lattice
  domains. Cargo.toml carries the crates.io-mandatory `description` + `license = "MIT"`
  + `repository` fields.
- **`morph-core@0.1.0`** — form alignment + landmark matching primitives, built on
  `csp-solver`. Depended on `csp-solver` via a registry version pin alongside the
  workspace-internal path (`csp-solver = { version = "0.1.0", path = ".." }`); the
  path resolved local builds, the version resolved the crates.io edge. _Excised to
  [`mkbabb/morph`]https://github.com/mkbabb/morph; `0.2.0` onward ships from there._

### npm (@mkbabb scope)

- **`@mkbabb/csp-solver-wasm@0.1.0`** — wasm-pack-emitted bindings for `csp-solver`.
  Published under the `@mkbabb/*` scope; emitted JS surface is `csp_solver_wasm.{js,d.ts,_bg.wasm}`.
- **`@mkbabb/morph@0.1.0`** — wasm-pack-emitted bindings for `morph-core`. The
  underlying Rust crate is named `morph`; the emitted JS surface is
  `morph.{js,d.ts,_bg.wasm}`. Consumed by bbnf-buddy through the npm registry.
  _Excised to [`mkbabb/morph`]https://github.com/mkbabb/morph; `0.2.0` onward
  ships from there. (`0.1.1` — the next patch — was the last release from this repo.)_