# Task 4: Deterministic RNG

**Depends on:** Task 1

## Context Files
- `.dev/2026-05-28-procgen-map-core/spec/design.md` — §4.4 (RNG) and §7 (determinism contract).
- `reikhelm-core/src/lib.rs` — append the module declaration here.

## Files
- Create: `reikhelm-core/src/rng.rs` — `Rng`.
- Modify: `reikhelm-core/src/lib.rs` — append `pub mod rng;`.

## What to Build
A deterministic RNG wrapping `rand_chacha::ChaCha8Rng` (spec §4.4). Reproducible across machines — never `thread_rng`. The keystone feature is `fork`: deriving an independent child stream from a **stable basis** (the originating seed) plus a label, so that forks are independent of draw order and of each other. The `Pipeline` (Task 6) calls `fork` once per pass; this is what makes editing the pipeline non-destructive to existing seeds (spec §7).

**Critical determinism detail:** `fork`'s label→seed mixing must be stable across runs and crate versions. Do **not** use `std::collections::hash_map::DefaultHasher` (unspecified, version-unstable). Use an explicit, fixed integer mix (e.g. a splitmix64 / FNV-style combine of the base seed and the label bytes). Document the chosen mixing.

## Interface Dependencies
- **Produces:** `Rng` with:
  - `from_seed(seed: u64) -> Self` (stores the seed as the fork basis)
  - `fork(&self, label: &str) -> Rng` — returns `Rng::from_seed(mix(self.basis_seed, label))`; **does not** advance `self`; order-independent.
  - `range(&mut self, lo: i32, hi: i32) -> i32` (half-open or inclusive — document which)
  - `chance(&mut self, p: f64) -> bool`
  - `choose<'a, T>(&mut self, items: &'a [T]) -> Option<&'a T>`
  - `shuffle<T>(&mut self, items: &mut [T])`

## Tests
- Same seed → identical sequence of `range` draws (reproducibility).
- `fork` is **order-independent**: `r.fork("a")` produces the same stream regardless of how many values were drawn from `r` beforehand.
- Distinct labels produce distinct (non-identical) streams: `fork("a") != fork("b")`.
- `fork("name#0")` and `fork("name#1")` differ (the occurrence-keying scheme the pipeline relies on works).
- `choose` on an empty slice returns `None`; `shuffle` is a permutation (same multiset).

## Success Criteria
- [ ] `Rng` wraps ChaCha8; `fork` derives from a stable basis with an explicit (non-`DefaultHasher`) mix.
- [ ] `fork` is order-independent and does not mutate the parent.
- [ ] `pub mod rng;` added to `lib.rs`.
- [ ] All tests pass: `cargo test -p reikhelm-core rng`

## Commit
`"feat(core): deterministic ChaCha8 RNG with order-independent fork"`
