# Project Conventions — reikhelm

Ground truth every dispatched agent reads. Plan lives at `.dev/2026-05-28-procgen-map-core/`.

## Toolchain & environment (CRITICAL)

- Rust **1.96.0** stable, `aarch64-apple-darwin`, via rustup.
- **`~/.cargo/bin` is NOT on the non-interactive shell PATH.** Every shell command that runs `cargo`, `rustc`, or `rustup` MUST first export it:
  ```sh
  export PATH="$HOME/.cargo/bin:$PATH"
  ```
  Put this at the front of the same Bash invocation as your cargo command. If you forget it you'll get `command not found: cargo`.
- Run all cargo commands from the workspace root `/Users/caspar/Projects/reikhelm`.

## Dependency versions (RESOLVED by Task 1)

- `rand` **0.10.1**, `rand_chacha` **0.10.0**, `rand_core` **0.10.1**, `serde` **1.0.228** (derive), `macroquad` **0.4.15**.
- This is the **rand 0.10** line — newer than 0.8/0.9. Verify exact API paths against the compiler: `ChaCha8Rng` implements `SeedableRng` (`seed_from_u64(u64)` / `from_seed([u8;32])`); `rand_core::RngCore` gives `next_u32`/`next_u64`. To minimize exposure to rand's churning trait paths (`SliceRandom`→`IndexedRandom`/`IndexedMutRandom` across 0.8→0.9), prefer building `range`/`chance`/`choose`/`shuffle` directly on `RngCore::next_u64` (e.g. Fisher–Yates shuffle from our own `range`) — also more transparent for determinism. `cargo build` is the arbiter.

## Git

- Repo is initialized in Task 1; work happens on the **default branch** (no feature branch — greenfield bring-up, explicitly authorized by the session goal).
- Each task commits with the exact message given in its task file's `## Commit` section.
- End every commit message body with this trailer (on its own line, preceded by a blank line):
  ```
  Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
  ```
- Commit only the files your task created/modified. Do not commit `/target` (gitignored).

## Module wiring ownership

- A task that CREATES a module file also appends its own `pub mod <name>;` to the parent (`lib.rs` or `passes/mod.rs` or `recipes/mod.rs`) — EXCEPT the parallel pass batch (Tasks 7–11): for those, the orchestrator pre-wires `passes/mod.rs` and pre-creates empty stub files, so pass implementers ONLY edit their own pass file and never touch `mod.rs`.

## Determinism rules (load-bearing — spec §7)

- All generation randomness flows through `reikhelm_core::rng::Rng` (ChaCha8). Never `thread_rng`/`rand::random()`.
- **Never `std::collections::hash_map::DefaultHasher`** for anything that affects generation — it's version-unstable. RNG `fork` uses an explicit integer mix (splitmix64 / FNV-style).
- No `HashMap`/`HashSet` *iteration order* may influence generated output (use sorted/`BTreeMap` or index order where order matters).
- Same seed → byte-identical `Map`, every run, every machine.

## Rust style

- Derive traits rather than hand-impl where possible (`Clone, Copy, Debug, PartialEq, Eq`, serde).
- Public items get a `///` doc comment. Keep functions small and total — no panics on valid input.
- Grid writes go through bounds-safe accessors; OOB is a no-op, never a panic (spec §8).
- Prefer iterators/combinators over index loops where it reads cleanly. This is a learning-Rust project: favor clear, idiomatic code over clever code.
- Tests live in an inline `#[cfg(test)] mod tests { use super::*; ... }` at the bottom of the module file.

## Reporting (for dispatched implementers)

End your report with a STATUS line: `DONE`, `DONE_WITH_CORRECTIONS`, `NEEDS_CONTEXT`, or `BLOCKED`.
Paste the **actual** `cargo test` output (not "tests pass"). List every file you created/modified. If you deviated from the task spec, say why.
