9.4 KiB
9.4 KiB
Best Practices Audit — Cleanup Findings
Generated by monkey swarm on 2026-06-30. Four specialist auditors reviewed
runtime,codegen,roto-tonic, and project-level structure.
Summary
| Severity | Count |
|---|---|
| Critical | 9 |
| Major | 17 |
| Minor | ~40 |
Critical Issues
1. BufMutBuilder panics instead of returning Err (runtime)
- File:
runtime/src/lib.rs:1038-1119 - Issue:
BufMutBuilderreturnsResult<()>on all write methods, but callsput_slicewhich panics if the underlyingBufMuthas no remaining capacity. UnlikeProtoBuilder, which checks bounds before every write,BufMutBuildernever actually produces anErr. - Fix: Check
self.buf.remaining_mut()before eachput_sliceand returnErr(RotoError::BufferOverflow), or remove theResultreturn type and document the panic contract.
2. #![no_std] + feature flags don't match reality (runtime)
- File:
runtime/src/lib.rs:1,runtime/Cargo.toml:9-12 - Issue: Crate declares
#![no_std]but has unconditionaluse bytes::BufMut. Thebytescrate requiresalloc(and transitivelystd). Theallocandstdfeature flags exist but don't gate any code. The crate can't compile inno_stdmode. - Fix: Gate
bytesbehind#[cfg(feature = "alloc")]or remove the feature flags and document that the crate requiresstd.
3. types.rs file corruption (codegen)
- File:
codegen/src/generator/types.rs:76 - Issue: Line 76 contains a shell artifact (
EOF > /opt/workspace/codegen/src/generator/types.rs) followed by a duplicated function body. The file likely won't compile. - Fix: Clean up the file immediately.
4. Massive code duplication in generator module (codegen)
- File:
codegen/src/generator/(all files) - Issue:
mod.rscontains full implementations ofwrite_message,write_enum,write_service,map_type_to_rust_accessor,to_pascal_case,to_snake_case,DATA_IMPORTS— all of which also exist inmessages.rs,services.rs,types.rs, andutils.rs. Only themod.rsversions appear to be used. - Fix: Either delete the split files (if
mod.rsis the single source of truth) or complete the refactor somod.rsre-exports the split modules.
5. ~50 .expect() panics in library generator code (codegen)
- File:
codegen/src/generator/mod.rs(all generator functions) - Issue: Malformed protos will crash the process instead of returning errors.
- Fix: Introduce a
GeneratorErrorenum and returnResult<Vec<…>, GeneratorError>from all generator functions.
6. Seven unused heavy dependencies in codegen (codegen)
- File:
codegen/Cargo.toml - Issue:
tonic,tower,bytes,http-body,http-body-util,tokio-stream,futures-utilare listed as dependencies but never used in the codegen library. They generate code that references these types via string literals — the generator itself doesn't need them. - Fix: Remove these from
Cargo.toml. This eliminates ~30+ transitive dependencies.
7. Edition 2024 / resolver = "3" requires nightly (workspace)
- File:
Cargo.toml:16, all crateCargo.toml - Issue:
resolver = "3"is only valid for Edition 2024, which is not yet stable. Norust-toolchain.tomlexists. This blocks adoption with stable Rust. - Fix: Add
rust-toolchain.tomlwithchannel = "nightly", or switch toedition = "2021"+resolver = "2".
8. No LICENSE file (workspace)
- Issue: The project cannot legally be used by others without a license.
- Fix: Add an MIT or Apache-2.0 license file.
9. StatusBody::new dead parameter (roto-tonic)
- File:
roto-tonic/src/lib.rs:118-125 - Issue:
StatusBody::new(data, status)takesstatus: u8but never uses it. The code hardcodes"0"into thegrpc-statustrailer. - Fix: Wire
statusinto the trailer value, or remove the parameter.
Major Issues
Runtime
| # | Issue | File | Fix |
|---|---|---|---|
| 1 | RotoMessage::decode(bytes::Bytes) forces heap allocation and blocks no_std |
lib.rs:74-77 |
Accept &[u8] instead |
| 2 | 7 core public types lack doc comments (MapFieldIterator, RotoOwned, RotoMessage, ProtoAccessor, ProtoBuilder, BufMutBuilder, FieldIterator, RepeatedFieldIterator) |
lib.rs |
Add /// doc comments |
Codegen
| # | Issue | File | Fix |
|---|---|---|---|
| 3 | codegen/src/runtime/mod.rs duplicates roto-runtime types (RotoError, Tag, WireType, read_varint, etc.) |
src/runtime/mod.rs |
Remove the duplicate; depend on roto-runtime |
| 4 | to_pascal_case has two implementations with different case-handling behavior |
mod.rs:28-38 vs utils.rs |
Consolidate to single canonical version |
| 5 | test_oneofs.rs is completely empty — tests nothing |
tests/test_oneofs.rs |
Implement or remove |
| 6 | All integration tests use hardcoded /tmp/ paths — won't run in parallel or on Windows |
tests/ |
Use std::env::temp_dir() or tempfile |
Roto-tonic
| # | Issue | File | Fix |
|---|---|---|---|
| 7 | BufferPool::get() / put() call .unwrap() on Mutex::lock() — aborts on poison |
src/lib.rs:96-109 |
Handle poison state or use tokio::sync::Mutex |
| 8 | Generated traits use native async (Edition 2024), but test impls use #[tonic::async_trait] — ABI mismatch |
src/generated/ + tests/ |
Remove #[tonic::async_trait] from test impls |
| 9 | .unwrap() on Response::builder().body() in 7+ places — panics in hot path |
src/generated/ |
Use .expect() or extract a helper |
| 10 | Missing cargo:rerun-if-changed for .proto files — changes don't trigger rebuild |
build.rs |
Add rerun directives |
| 11 | build.rs hardcodes target/debug/protoc-gen-roto — breaks release and cross-compile |
build.rs |
Use OUT_DIR or workspace-level coordination |
| 12 | tokio = { features = ["full"] } pulls all subsystems for a library that only needs net |
Cargo.toml |
Move to [dev-dependencies] |
| 13 | RotoDecoder::decode converts all errors to Status::internal() — no mapping of error variants |
src/lib.rs:78 |
Match RotoError variants to specific gRPC status codes |
| 14 | StatusBody fields are pub — breaks encapsulation |
src/lib.rs:112-126 |
Make fields private; add consumer methods |
Project Structure
| # | Issue | File | Fix |
|---|---|---|---|
| 15 | No [workspace.dependencies] — shared deps duplicated across crates, risking version drift |
Cargo.toml |
Define workspace-level dependency table |
| 16 | interop_test.rs asserts is_ok() on UNIMPLEMENTED call — tests wrong behavior |
tests/interop_test.rs |
Assert is_err() with UNIMPLEMENTED status |
| 17 | No CI configuration, no clippy.toml, no .rustfmt.toml — code quality not enforced |
Project root | Add GitHub Actions + config files |
| 18 | roto/roto/ stray directory and grpc_bench/ empty submodule |
Project root | Clean up stale directories |
| 19 | panic = "abort" in [profile.dev] is too aggressive for a library |
Cargo.toml |
Remove from dev profile; keep only in release |
| 20 | protos/ crate has no purpose (single hello() function) |
protos/ |
Remove or give it a real purpose |
Minor Issues (Selected)
Runtime
ProtoAccessor::newreturnsResultbut never fails — change to direct constructorwrite_int32doesn't use zigzag encoding — document this or addwrite_sint32RepeatedFieldIterator::new_rangesilently tolerates out-of-bounds ranges- Tests gated behind
#[cfg(feature = "alloc")]may be silently skipped RotoErrorlackssource()chaining — considerthiserror
Codegen
- Missing
#[must_use]on public generator functions - No crate-level or function-level documentation
- Magic numbers for protobuf field types/labels (1-18)
env_logger::init()is deprecated — useinit_from_env()edition = "2024"withoutrust-versionkey- Utility functions (
to_pascal_case,to_snake_case) arepubbut should bepub(crate)
Roto-tonic
#![allow(unused, ...)]blanket suppresses important lints in generated codetokio::time::sleep(100ms)race condition intest_server_start- Server task spawned but never joined/aborted in
interop_test.rs - Missing
#[derive(Debug)]onBufferPool,StatusBody - Error response body
[0, 0, 0, 0, 0]should be a named constant Infallibleerror type hides panic sites
Project
excludelist incomplete — test temp dirs not listedCargo.lockshould be committed (it is, but no.gitignoreexception).descfiles may be generated artifacts that should be regenerated, not checked in- No
rust-toolchain.tomldespite Edition 2024 requirement - No
[workspace.metadata]for crates.io readiness allocfeature flag oncodegenandbenchesis meaningless for CLI/benchmark crates
Positive Observations
The project has several strengths:
- Zero
unsafecode — all memory operations in the runtime use safe slice indexing - Consistent error handling — all fallible operations return
Result<T, RotoError> - No panics in library code —
unwrap()/expect()appear only in tests - RevBuilder is a creative, well-implemented design for reverse-direction encoding
- 18 unit tests in the runtime with good edge-case coverage
- Comprehensive README with design rationale, API examples, and benchmark comparisons
- Well-structured workspace with clear crate boundaries