field-cat 0.1.0

Finite field algebra shared across plonkish-cat, proof-cat, and stark-cat
Documentation
# CLAUDE.md — Rust Project Conventions

## Philosophy

This project follows **functional**, **type-driven**, and **domain-driven** design principles.  The type system is the primary tool for correctness.  If a state is illegal, it should be unrepresentable.

## Architecture

- **Modules by domain context**, not by technical layer.  No `controllers/`, `services/`, `models/` splits.
- Each bounded context gets its own module with its own types.  Cross-context communication happens through well-defined public interfaces.
- Prefer thin `main.rs`/`lib.rs` that wires contexts together.

## Types

- **Newtypes** for all domain primitives.  Never pass raw `String`, `u64`, `f64`, etc. across function boundaries when they carry domain meaning.
- **Sum types (enums)** to model domain variants and state machines.  Prefer enums over booleans or stringly-typed fields.
- **Phantom types** where compile-time state tracking is warranted.
- **No public struct fields**.  All fields must be private.  Expose access through getter methods and construct through associated functions or builder patterns.
- `#[must_use]` on pure functions and types whose values should not be silently dropped.

## Error Handling

- A single project-wide `Error` enum defined in a dedicated `error` module.
- Each variant wraps an underlying error type from a dependency or domain context.
- Implement `From<UnderlyingError> for Error` for every variant to enable `?` ergonomics throughout the codebase.
- Implement `std::fmt::Display` and `std::error::Error` by hand, no `thiserror`, no `anyhow`.
- Domain logic returns `Result<T, Error>`.  Never panic in library code.

## Style

- **Prefer `match` over `if`/`else`**.  The only exception is when branching on a `bool` value, where `if`/`else` is preferred.  For everything else, use `match`.
- **No `return` keyword**.  Every function body is a single expression.  Use `?` for early error propagation and combinators for control flow; never write an explicit `return`.
- **No `mut`**.  All bindings and parameters must be immutable.  Restructure with shadowing, combinators, or new bindings instead of mutation.
- **Combinators** (`map`, `and_then`, `filter`, `fold`, etc.) over imperative loops and match-and-early-return, where they remain readable.
- **Never match on `Option<_>`**.  Use combinators instead: `map`, `and_then`, `unwrap_or`, `unwrap_or_else`, `filter`, `zip`, etc.
- **Prefer combinators on `Result<_, _>`**.  Use `map`, `map_err`, `unwrap_or`, `unwrap_or_else`, `and_then`, etc. instead of pattern matching on `Ok`/`Err`.  Reserve `match` on `Result` only when the arm logic is too complex for a single combinator chain.
- **Prefer `and_then` over nested pattern-matching**.  When you would nest `match` arms to unwrap successive `Option`/`Result` layers, flatten with `and_then` (or `?`) instead.
- **Pure functions** — isolate side effects at the boundaries.  Core domain logic takes values and returns values.
- **No `unwrap()`/`expect()`**.  Prohibited everywhere — including tests and `main`.  Always propagate or handle errors explicitly.
- **No `loop` or `for`**.  Use iterator combinators (`map`, `filter`, `fold`, `for_each`, etc.) or recursion.  If you think you need a loop, restructure with combinators or a recursive function.
- **No `scan`**.  Use `successors`, `fold`, or recursion instead.
- **No reference counting** (`Rc`, `Arc`).  Prefer ownership, borrowing, and lifetime parameters.
- **No naked `as` casts**.  Never use `as` for type conversions.  Use `From`/`Into` for infallible conversions and `TryFrom`/`TryInto` for fallible ones.
- **No panicking indexing**.  Never use `a[i]` or `a[i..j]`.  Use `.get()` / `.get(range)` and handle the `None` case explicitly.
- Prefer **iterators** over indexed access.

## Traits

- Trait definitions follow domain boundaries: a trait represents a domain capability, not a technical pattern.
- **No dynamic polymorphism**.  Never use `dyn Trait` or trait objects.  All dispatch must be static via generics or `impl Trait`.
- **Implement the standard trait, not an ad-hoc method**.  If a method's signature and semantics match a trait from `core`/`std` (e.g., `Add`, `Sub`, `Mul`, `From`, `Into`, `Display`, `Iterator`, etc.), implement the trait instead of defining a standalone method.

## Linting

- **Always run `RUSTFLAGS="-D warnings" cargo clippy`** before considering code complete.  All warnings are errors, code must pass cleanly.

## Testing

- **Property-based tests** via `proptest` where types suggest invariants.
- Unit tests live in the same file as the code they test (`#[cfg(test)]` modules).
- Integration tests go in `tests/` organized by domain context, not by module path.
- Test names describe the property or behavior, not the function name.

## Dependencies

- Minimize dependencies.  Evaluate whether a crate is truly needed or if the functionality can be expressed with `std` and the type system.
- No `thiserror`, no `anyhow`, error handling is explicit and hand-rolled (see above).

## Documentation

- **Doc comments on all public items**.  Every public type, function, trait, method, and module must have `///` doc comments.  Use `//!` at the top of `lib.rs` and major modules for module-level documentation.
- **Include `# Examples` sections** with runnable code blocks in doc comments for key public APIs.  These double as doctests.
- **No `unwrap()`, `expect()`, or `unreachable!()` in documentation**.  All code examples in doc comments, README, and any markdown must use `?`, combinators, or explicit handling instead.
- **Use [`backtick links`]** to cross-reference other types, traits, and functions within doc comments.
- **Preview locally** with `cargo doc --no-deps --document-private-items --open`.
- **Run doctests** as part of the test suite: `cargo test --doc`.
- **Docs are auto-published** to GitHub Pages via `.github/workflows/docs.yml` on push to `main`.