Files
rustfs/crates/AGENTS.md
T
安正超 b5e565c0ce chore(agents): add Rust code quality rules and skill (#3144)
* docs: update security advisory lessons

* chore(agents): add Rust code quality rules and skill

Add rules derived from full-project code review (48 findings across
7 dimensions) to prevent recurring issues in agent-generated code.

AGENTS.md changes:
- crates/AGENTS.md: error type design, concurrency, recursion safety,
  type casting, test quality rules
- root AGENTS.md: serde safety, naming conventions
- crates/ecstore/AGENTS.md: allocation discipline, lock ordering,
  recursion safety, dead code policy
- crates/notify/AGENTS.md: lock ordering for runtime_view/facade

Skill changes:
- code-change-verification: add Rust-specific checks (unwrap, as cast,
  clone, lock order, recursion, error types, test assertions)
- security-advisory-lessons: add serde deserialization safety pattern
- NEW rust-code-quality: automated scan + manual review checklist
2026-05-31 22:19:36 +08:00

56 lines
3.1 KiB
Markdown

# Crates Instructions
Applies to all paths under `crates/`.
## Library Design
- Treat crate code as reusable library code by default.
- Prefer `thiserror` for library-facing error types.
- Do not use `unwrap()`, `expect()`, or panic-driven control flow outside tests.
## Testing
- Keep unit tests close to the module they test.
- Keep integration tests under each crate's `tests/` directory.
- Add regression tests for bug fixes and behavior changes.
## Error Type Design
- Public API functions must return a typed error enum (preferably `thiserror`-derived), never `Result<_, String>`.
- Do not use `Box<dyn Error>` or `Box<dyn Error + Send + Sync>` in public trait methods or struct methods. Define a concrete error type with specific variants.
- When implementing `std::error::Error`, always override `fn source()` if you store an inner error. Breaking the error chain makes debugging impossible.
- Internal helpers that return `Result<_, String>` and are immediately wrapped via `.map_err(Error::other)` should return the actual error type directly.
## Concurrency
- Document lock acquisition order when a module uses multiple locks. Never acquire the same set of locks in different orders across code paths.
- Never hold a `tokio::sync::RwLock`/`Mutex` write guard across `.await` points unless the critical section is unavoidably async and the hold time is bounded.
- Prefer `compare_exchange` loops over load-then-store for concurrent counters (peak values, adaptive heuristics).
- When resetting multi-field atomic statistics, use a version/sequence counter or accept that concurrent readers may see partial snapshots; document the tradeoff.
- `std::sync::Mutex` is acceptable in async context only when held for a brief, non-`await`-containing critical section. If in doubt, use `tokio::sync::Mutex`.
## Recursion Safety
- Recursive tree/graph traversals must have a depth limit (e.g., `max_depth` counter) or use an iterative approach with an explicit `Vec` stack.
- This applies to cache trees, directory walks, and any user-influenced hierarchy.
- A corrupted or malicious input must not be able to overflow the thread stack.
## Type Casting
- Never use `as` for numeric conversions that may truncate or overflow. Use `try_into()` with explicit error handling, or clamp with `value.max(0) as usize` when the domain is bounded.
- `f64 as usize` saturates but is fragile; clamp to `[0, usize::MAX as f64]` first.
- Treat every `as` cast in a PR review as a potential bug; require justification.
## Testing
- Keep unit tests close to the module they test.
- Keep integration tests under each crate's `tests/` directory.
- Add regression tests for bug fixes and behavior changes.
- Every test function must contain at least one `assert!`/`assert_eq!`/`assert_matches!`. A test that only calls code without asserting is not a test.
- In tests, prefer `.expect("context: what was being tested")` over bare `.unwrap()`. A test failure should tell you which operation failed and with what input.
## Async and Performance
- Keep async paths non-blocking.
- Move CPU-heavy operations out of async hot paths with `tokio::task::spawn_blocking` when appropriate.