| name | deep-review |
| description | Run a deep code review across the manifold-csg crates |
| user-invocable | true |
Deep Review
Run a thorough code review of the manifold-csg workspace. Check all crates/ source files.
Arguments
- No arguments: review the entire codebase
- A file path or glob: review only matching files (e.g.,
crates/manifold-csg/src/manifold.rs)
since release: review only files changed since the last release tag (use git diff --name-only $(git describe --tags --abbrev=0)..HEAD -- '*.rs' to get the list)
staged: review only staged files (git diff --cached --name-only -- '*.rs')
branch: review only files changed on the current branch vs main (git diff --name-only main...HEAD -- '*.rs')
Review Categories
Work through each category in order. For each finding, cite the file and line number.
1. Idiomatic Rust
Review as the pickiest expert Rust reviewer. Look for:
- Anti-patterns and non-idiomatic code
- Misuse of language features (lifetimes, traits, enums, error handling)
- Places where
Result should replace bool/Option, enums should replace strings, named structs should replace tuples
- Missing standard trait implementations (Display, From, Default, etc.)
- Unnecessary clones, allocations, or copies
- Iterator chains that could replace manual loops
2. Code Smells
- Dead code (unused functions, imports, fields, variants)
- Duplicate code — check across crates, not just within files
- Functions that are too long or do too many things
- Refactoring opportunities (extract function, simplify conditionals)
- Magic numbers that should be named constants
3. FFI Safety & Resource Management
This is the highest-risk area for a bindings crate. Verify:
- Every C allocation (
manifold_alloc_*) is paired with deallocation (manifold_delete_*) on ALL paths including error returns and panics
Drop implementations null-check before freeing
- No double-free paths — verify ownership transfer semantics in batch operations, decompose, etc.
unsafe impl Send on Manifold and CrossSection — justification still valid? Check upstream C++ for any new thread-local state or shared mutable state
Sync is deliberately NOT implemented — verify this is still correct (check for mutable shared_ptr<CsgNode> pNode_ in upstream)
- No panic-across-FFI risk — if a Rust panic unwinds through C frames, it's UB. Check that no panic-capable code runs inside FFI call sequences
- Integer casts at the FFI boundary (u32↔u64, usize→c_int) — check for truncation/overflow
- Pointer validity — every raw pointer dereference must have a preceding validity argument (allocation or invariant)
- Buffer size correctness — when copying data out via
manifold_meshgl*_vert_properties / manifold_meshgl*_tri_verts, verify buffer sizes match what the C API expects
ManifoldManifoldPair — verify both returned pointers are always consumed (no leak if caller ignores one half of a split)
Build script (build.rs) correctness for cross-compile:
cfg!(target_os = ...) / cfg!(target_arch = ...) / cfg!(target_env = ...) in build.rs is a footgun when used to detect the target — these macros evaluate at the build-script-host's compile time, NOT the target's. Coincidentally correct as long as we never cross-compile; fails silently the moment we do (e.g. wasm). Use env::var("CARGO_CFG_TARGET_OS") / ..._ARCH / ..._ENV instead. (cfg! is fine when you genuinely want host-side detection — e.g., picking a shell command for the build script's own use.)
cargo:rustc-link-arg=FLAG from a sys crate's build.rs does NOT propagate to downstream link invocations — only rustc-link-lib and rustc-link-search do. The proper sys-crate idiom for forwarding link flags: emit cargo:KEY=VALUE (Cargo translates this into DEP_<UPPERCASE_LINKS>_<UPPERCASE_KEY> env var visible to dependents), and have the safe wrapper crate's build.rs read it and re-emit cargo:rustc-link-arg=.... End-user binaries then need a similar build.rs (or .cargo/config.toml). Flag any cargo:rustc-link-arg=... in a sys crate that isn't backed by this pattern.
- The artifact-typed variants (
cargo:rustc-link-arg-bins=, -tests=, -cdylib=) are only legal from crates that declare those targets — a library-only sys crate can't use them (cargo rejects with "package does not have a bin target"). Flag any of these in a crate that doesn't have the matching target.
CI cache key correctness (actions/cache + cmake builds):
- cmake's
CMakeCache.txt records absolute paths (toolchain file, source dir, -D options). If a cached target/ is restored on a run where any of those paths differ — including from a different OUT_DIR layout, a different emsdk install location, or a different CMakeLists.txt source dir — cmake refuses with "source does not match the source used to generate cache." We've been bitten by this twice: once on the Emscripten lane (emsdk path moved between runs), once on the wasm32-uu lane (source dir moved when adopting the shim's CMake helper).
- The footgun is
restore-keys being too permissive. restore-keys does prefix matching, so if the prefix is just ${runner.os}-cargo-<lane>-<cache-version>-, ANY old cache for that lane gets pulled in — even one built with an incompatible cmake source dir.
- Fix pattern: split the cache
key so layout-affecting inputs (env vars like EMSDK, files like build.rs and wasm32-uu/**) are part of the restore-keys PREFIX, while frequently-changing inputs (Cargo.lock, lower-level build.rs files) live in the suffix. That way changing a layout input shifts the prefix → no incompatible cache restored. Look for any cache stanza whose restore-keys doesn't include the same prefix-segments as the key for inputs that affect cmake's recorded paths.
- The
cache-version bump file is the manual escape hatch when caches go bad — it busts every lane's cache. Useful as a one-shot recovery, but not a substitute for fixing the key structure.
4. Numerical Precision
Precision is our key differentiator (f64/MeshGL64). Verify:
- f64 precision is used by default everywhere — no accidental f32 narrowing
from_mesh_f32 / to_mesh_f32 paths are clearly documented as lossy
- No unnecessary f64→f32→f64 round-trips in internal code paths
- Extrude and other operations that bridge CrossSection↔Manifold don't silently lose precision through intermediate polygon representations
- Tolerance/epsilon values used in triangulation and offset operations are documented and appropriate
5. API Completeness
We bind the complete manifold3d v3.4.1 C API (256 functions in manifold-csg-sys). The review focus is on maintaining completeness and ensuring the safe layer covers everything useful.
Sys crate vs upstream header:
- Read the manifold3d C header (
manifoldc.h, built during compilation at target/*/build/manifold-csg-sys-*/out/build/_deps/manifold-src/bindings/c/include/manifold/manifoldc.h) and diff against manifold-csg-sys/src/lib.rs
- If we've updated the pinned manifold version, check for newly added C API functions that need binding
- Verify all function signatures still match the header (parameter types, return types) — ABI drift from upstream changes
Safe wrapper coverage:
- For every function group bound in
manifold-csg-sys, verify there is a corresponding safe method in manifold-csg. Flag sys-level functions that have no safe wrapper yet. Prioritize by usefulness.
- Specifically check: are all callback-based APIs (warp, set_properties, level_set, write_obj) wrapped safely? These are the hardest to get right.
- Are all MeshGL/MeshGL64 advanced accessors (merge, run_index, face_id, tangents) exposed through the safe
MeshGL/MeshGL64 types?
- Are the quality globals (
set_min_circular_angle, set_circular_segments, etc.) exposed? If so, are they documented as affecting global state?
Feature flag coverage:
- Does the
nalgebra feature cover all methods that take/return geometric types (vectors, points, matrices)?
- Are there other popular geometry crates that should have optional integration (e.g.,
glam, mint)?
6. API Ergonomics
Review the safe API from a user's perspective:
- Are method signatures intuitive? Would a first-time user understand the parameter order?
- Are there missing convenience methods? (e.g.,
Manifold::translate_z(), CrossSection::offset_round())
- Should any methods accept
impl Into<T> for flexibility?
- Are builder patterns appropriate anywhere? (e.g., extrude with optional twist/scale)
- Error types — are they specific enough to be actionable? Can users match on error variants?
- Does the re-export structure in
lib.rs give users a clean import experience?
- Are operator overloads (
+, -, ^) discoverable and documented?
- Should
Manifold::extrude be an associated function or a method on CrossSection?
C/C++ API parity (critical — many users will transition from the C/C++ library):
- For every safe wrapper method, compare parameter order and types against the corresponding C function in
manifoldc.h. Flag any reordering, renamed parameters, or hidden defaults that would surprise a C/C++ user.
- Check that optional/defaulted parameters match C API defaults. If a Rust wrapper omits a C parameter (e.g.,
center, slices, twist), verify there's either a sensible default or a _with_options variant that exposes full control.
- Check consistency: do similar functions handle the same parameter the same way? (e.g.,
cube, cylinder, and CrossSection::square should all handle center identically — not some hardcoded and some exposed)
- Verify the layout/ordering of array parameters matches C conventions (e.g.,
transform's column-major [f64; 12] should document the mapping to C's 12 individual params)
- Check that enum variant names are recognizable to C users (e.g.,
JoinType::Round maps obviously to MANIFOLD_JOIN_TYPE_ROUND)
- Where Rust packs multiple C params into an array (e.g.,
normal: [f64; 3] instead of nx, ny, nz), verify this is documented
7. Test Coverage & Quality
Assess the test suite:
- Untested public functions — every public method in the safe API should have at least one test
- Edge cases — empty inputs, zero-size primitives, very large/small values, degenerate geometry
- Negative testing — do error paths get exercised? (invalid meshes, empty polygons, etc.)
- Thread safety — is Send tested with actual thread spawning, not just compile-time assertions?
- Round-trip fidelity — are mesh export→import round-trips tested for volume/vertex preservation?
- Test isolation — do tests depend on execution order or shared mutable state?
#[ignore] tests — are they still relevant or should they be deleted/fixed?
- Assertion quality — are tests checking meaningful properties or just "doesn't panic"?
- Multi-target gating: tests that depend on host-OS facilities (
std::thread::spawn, filesystem, sockets, signals) should be gated with #[cfg_attr(target_os = "...", ignore = "explanation")] for targets that lack them. The ignore reason should explain why it's ignored on this target, not just that it is.
- For cross-compiled targets without a native runner (wasm, embedded), check whether
CARGO_TARGET_<TRIPLE>_RUNNER is configured (.cargo/config.toml, CI workflow env). Without a runner, "build clean" doesn't tell us tests pass.
8. Examples & Documentation Artifacts
Verify the documentation artifacts are consistent with the code:
Examples (crates/manifold-csg/examples/):
- Do all examples compile and run without errors? (
cargo run -p manifold-csg --example basics, etc.)
- Do examples cover the main entry points: primitives, booleans, transforms, 2D cross-sections, extrusion, SDF, OBJ I/O, and threading?
- Are examples free of
unwrap() on fallible operations without explanation?
- Do examples demonstrate idiomatic usage patterns that new users should follow?
API coverage table (API_COVERAGE.md):
- Does the table account for every function declared in
manifold-csg-sys/src/lib.rs?
- Are the safe wrapper links accurate (correct file and line number)?
- Are "Internal" and "Not wrapped" statuses correct?
- Does the summary count match the detailed tables?
- Has the table been updated after any API additions or removals?
README:
- Are feature descriptions accurate and consistent with the code?
- Do quick-start examples compile?
- Are links to examples/, API_COVERAGE.md, and source files valid?
9. Packaging & Publishing Correctness
Review everything a crate maintainer needs for correct, user-friendly publishing:
Versioning scheme (see CLAUDE.md):
manifold-csg-sys version = {upstream_major}.{upstream_minor}.{100+our_release} (e.g., 3.4.100). Verify the version matches the manifold3d tag pinned in build.rs.
manifold-csg version = standard semver (0.x.y), independent of upstream. Its dependency on manifold-csg-sys must pin the correct sys version.
- When the manifold3d pin is bumped, the sys crate version MUST be updated to match. Flag any mismatch.
Cargo.toml correctness:
package.description — present, concise, accurate for both crates
package.documentation — points to docs.rs (or will auto-generate)
package.readme — set if README exists
package.keywords and package.categories — set and relevant (max 5 keywords). Good keywords for discoverability: csg, geometry, mesh, manifold, 3d
package.exclude / package.include — exclude test fixtures, build artifacts, CI config from the published crate
links key in sys crate — correctly set to prevent duplicate linking
- Edition — using latest stable edition? (currently 2024)
Dependency hygiene:
- Are all dependencies at their latest compatible versions? (
cargo update --dry-run)
- Are dev-dependencies correctly scoped? (nothing test-only leaking into the main dependency tree)
build-dependencies — cmake version current?
- Feature flags — are there any that should exist? (e.g.,
parallel for TBB, nalgebra for convenience conversions)
Publishing readiness:
cargo publish --dry-run for both crates — does it succeed?
- Crate size — is the published crate reasonably small? (no vendored C++ source, no build artifacts)
- License files —
LICENSE-APACHE and LICENSE-MIT present and referenced in Cargo.toml
links = "manifold" — will this conflict with other -sys crates linking the same library? Document how users should handle this.
Ecosystem & Cargo evolution:
- Is the
resolver = "2" setting still the recommended default, or has a newer resolver landed?
- Are there new Cargo features (e.g., artifact dependencies, public/private dependencies via
dep:, lints table changes) that would improve the crate?
- Are there upcoming Rust edition changes that affect this code? (e.g., new
unsafe extern syntax was stabilized in 2024 edition — are we using it?)
- Check
rust-version (MSRV) — should we declare one? What's the minimum Rust version that compiles this?
- Are there new crates.io policies (e.g., trusted publishing, provenance attestations) we should adopt?
Documentation:
- Crate-level
//! docs — present, has example code, links to upstream manifold3d
#[doc(hidden)] on internal items that leak through pub(crate)
- Do doc-tests compile? (currently ignored with
rust,ignore — can they be made runnable?)
10. Upstream Compatibility
This crate tracks manifold3d upstream. Verify:
- Pinned version in
build.rs — what version are we on? What's latest? What changed?
- ABI compatibility — have any C API function signatures changed in newer manifold3d releases?
- Deprecated functions — are we binding any C API functions that upstream has deprecated?
- wasm32-unknown-unknown cfg-gates may need revisiting. Grep for
target_os = "unknown" across the workspace. Each gated FFI declaration / safe wrapper / test is gated because that C API surface postdates the shim's tested manifold pin. When the shim's tested pin moves to (or past) our host pin, those gates can be removed. The OBJ I/O gates (manifold_*_obj) are gated for a different reason (iostream patches strip them) and stay regardless.
- New capabilities — has upstream added significant new C API surface (new types, new operations) that we're missing?
- Build system changes — has manifold3d changed its CMake structure, added/removed FetchContent deps, changed library names?
- Known upstream bugs — check manifold3d issues for bugs affecting functions we bind (especially boolean operations, MeshGL64, CrossSection offset)
11. Dependency Audit
- Check all Cargo dependencies are at their latest published version — run
cargo update --dry-run and flag anything that can be bumped
- Check C++ dependencies in
build.rs — the manifold3d tag is pinned there. Check github.com/elalish/manifold/releases for newer releases. Manifold also pulls Clipper2 and TBB via CMake FetchContent (versions controlled by manifold's CMakeLists.txt)
- Known issues in upstream crates or C++ libraries
- License concerns — warn on any copyleft/viral license (GPL, LGPL, AGPL, SSPL). Note: manifold3d is Apache-2.0, Clipper2 is Boost, TBB is Apache-2.0 — all compatible
- Unnecessary or redundant dependencies
Output Format
Group findings by category. For each finding:
**[Category] file.rs:123** — Short description of the issue.
Suggested fix or explanation.
Assign each finding a severity:
- error: Correctness bug, unsoundness, undefined behavior, memory safety violation
- warning: Likely bug, missing safety check, precision loss, incomplete API
- note: Style, ergonomics, documentation, nice-to-have improvement
At the end, provide a summary: total findings per category, severity breakdown (error/warning/note), and recommended priority order for fixes.
If a category has zero findings, say so explicitly — don't skip it silently.