Files
roto/CLEANUP.md
T
2026-06-30 00:49:03 -04:00

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: BufMutBuilder returns Result<()> on all write methods, but calls put_slice which panics if the underlying BufMut has no remaining capacity. Unlike ProtoBuilder, which checks bounds before every write, BufMutBuilder never actually produces an Err.
  • Fix: Check self.buf.remaining_mut() before each put_slice and return Err(RotoError::BufferOverflow), or remove the Result return 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 unconditional use bytes::BufMut. The bytes crate requires alloc (and transitively std). The alloc and std feature flags exist but don't gate any code. The crate can't compile in no_std mode.
  • Fix: Gate bytes behind #[cfg(feature = "alloc")] or remove the feature flags and document that the crate requires std.

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.rs contains full implementations of write_message, write_enum, write_service, map_type_to_rust_accessor, to_pascal_case, to_snake_case, DATA_IMPORTS — all of which also exist in messages.rs, services.rs, types.rs, and utils.rs. Only the mod.rs versions appear to be used.
  • Fix: Either delete the split files (if mod.rs is the single source of truth) or complete the refactor so mod.rs re-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 GeneratorError enum and return Result<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-util are 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 crate Cargo.toml
  • Issue: resolver = "3" is only valid for Edition 2024, which is not yet stable. No rust-toolchain.toml exists. This blocks adoption with stable Rust.
  • Fix: Add rust-toolchain.toml with channel = "nightly", or switch to edition = "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) takes status: u8 but never uses it. The code hardcodes "0" into the grpc-status trailer.
  • Fix: Wire status into 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::new returns Result but never fails — change to direct constructor
  • write_int32 doesn't use zigzag encoding — document this or add write_sint32
  • RepeatedFieldIterator::new_range silently tolerates out-of-bounds ranges
  • Tests gated behind #[cfg(feature = "alloc")] may be silently skipped
  • RotoError lacks source() chaining — consider thiserror

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 — use init_from_env()
  • edition = "2024" without rust-version key
  • Utility functions (to_pascal_case, to_snake_case) are pub but should be pub(crate)

Roto-tonic

  • #![allow(unused, ...)] blanket suppresses important lints in generated code
  • tokio::time::sleep(100ms) race condition in test_server_start
  • Server task spawned but never joined/aborted in interop_test.rs
  • Missing #[derive(Debug)] on BufferPool, StatusBody
  • Error response body [0, 0, 0, 0, 0] should be a named constant
  • Infallible error type hides panic sites

Project

  • exclude list incomplete — test temp dirs not listed
  • Cargo.lock should be committed (it is, but no .gitignore exception)
  • .desc files may be generated artifacts that should be regenerated, not checked in
  • No rust-toolchain.toml despite Edition 2024 requirement
  • No [workspace.metadata] for crates.io readiness
  • alloc feature flag on codegen and benches is meaningless for CLI/benchmark crates

Positive Observations

The project has several strengths:

  • Zero unsafe code — all memory operations in the runtime use safe slice indexing
  • Consistent error handling — all fallible operations return Result<T, RotoError>
  • No panics in library codeunwrap()/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