Guidance for agentic coding agents working with petite-ad.
Build directory: ~/.cache/rust-build/ (cached, never mention in docs)
Edition: Rust 2021 | License: MIT OR Apache-2.0
# Build & check
cargo build --release # Build optimized release
cargo check # Quick syntax check
cargo fmt # Auto-format code
cargo clippy --all-targets --all-features -- -D warnings # Lint with strict warnings
# Testing
cargo test # Run all tests
cargo test test_name -- --nocapture # Run specific test with output
cargo test --lib # Library tests only
cargo tarpaulin --lib --out Stdout # Generate coverage report
# Benchmarking
cargo bench # Run benchmarks
cargo bench --no-run # Check benchmarks compile without runningCore Library (src/lib.rs): MonoAD, MultiAD, MonoAD2RR, MonoAD2FR, MonoAD2RF, GraphBuilder
Modules:
src/mono/- Single-variable automatic differentiationsrc/multi/- Multi-variable automatic differentiationsrc/error.rs- Error types (AutodiffError)src/macros.rs- Macros (mono_ops!,multi_ops!)
Tests: Unit tests in src/*/tests.rs, comprehensive tests in src/tests_comprehensive.rs
Benchmarks: benches/compute_benchmark.rs, benches/hessian_benchmark.rs
- Standard library first, then external crates, then internal modules (separated by blank lines)
- Use explicit imports for clarity
- Re-export public types in
lib.rsfor API simplicity - Use
crate::Resultfor error-returning functions
- Functions:
snake_case, methods starting with action verbs (compute_,forward_,backward_) - Types:
PascalCasefor structs/enums/traits - Constants:
SCREAMING_SNAKE_CASE - Private helpers: Prefix internal functions with underscore if needed
- Type annotations: Always explicit for public functions and struct fields
- Use
crate::Result<T>(alias forstd::result::Result<T, AutodiffError>) - Use
?operator for propagation - Document error conditions in doc comments
- Use
#[inline]and#[inline(always)]for hot functions - Pre-allocate vectors with
with_capacity()when size is known - Capture computed values in closures to avoid recomputation
- Use mold linker for faster builds (configured in
.cargo/config.toml)
- Public items: Full doc comments
///with examples - Complex logic: Explain the "why" not the "what"
- Inline comments: Use
//for clarification, keep minimal - Tests: Include usage examples in doc comments for public APIs
- 4-space indentation (enforced by
cargo fmt) - Max line length: ~100 characters (soft limit)
- One statement per line; use temporary variables for readability
All commits run: cargo fmt --check → cargo clippy -- -D warnings → cargo test --all-features
❌ NEVER use git commit --no-verify - This bypasses all pre-commit checks and will likely cause CI failures.
If you used --no-verify and CI fails:
- Fix the issues (usually formatting: run
cargo fmt) - Re-stage files:
git add . - Commit without
--no-verify:git commit -m "fix: ..." - Push and verify CI passes
| Failure | Cause | Fix |
|---|---|---|
cargo fmt |
Code formatting | Run cargo fmt then re-stage |
cargo clippy |
Lint warnings | Fix warnings or run cargo clippy --fix |
cargo test |
Test failures | Fix failing tests |
The CI workflow (.github/workflows/ci.yml) runs:
- Test matrix: Rust stable and nightly
- Coverage: Code coverage with cargo-tarpaulin
- Security audit: cargo-audit for vulnerability checking
After pushing any commit, agents MUST verify CI passes:
- Push commit and note the run ID
- Run
gh run watch --repo leafyoung/petite-ad --exit-statusuntil completion - If CI fails, run
gh run view --log-failed --repo leafyoung/petite-adto diagnose - Fix any issues and re-push until all jobs pass
- Only proceed to next task after CI is green
# View CI run status (get run ID from push output or list)
gh run list --repo leafyoung/petite-ad --limit 3
# Watch CI run progress with live updates
gh run watch <run-id> --repo leafyoung/petite-ad --exit-status
# If CI fails, view detailed failure logs
gh run view <run-id> --repo leafyoung/petite-ad --log-failed
# View specific job logs
gh run view <run-id> --repo leafyoung/petite-ad --job <job-id>// ✅ Good: Pre-allocate with capacity, inline hot functions
#[inline]
pub fn compute(exprs: &[MonoAD], x: f64) -> f64 {
let mut value = x;
for expr in exprs {
value = expr.forward(value);
}
value
}// ✅ Good: Capture computed values in closures
MonoAD::Sin => {
let y = x.sin();
let x_cos = x.cos(); // Capture to avoid recomputation
let grad = Box::new(move |dy: f64| -> f64 { dy * x_cos });
(y, grad)
}// ✅ Good: Use Result type alias and ? operator
pub fn compute(exprs: &[(MultiAD, Vec<usize>)], inputs: &[f64]) -> Result<f64> {
let mut values: Vec<f64> = inputs.to_vec();
// ... operations with ? for error propagation
Ok(values.last().copied().unwrap_or(0.0))
}- ❌ Never:
cargo clean(breaks build cache) - ❌ Never: Use
git commit --no-verify(bypasses pre-commit checks) - ❌ Never: Commit
Cargo.lockif this is a library (only for binaries) - ✅ Always: Use
cargo testbefore committing - ✅ Always: Run
cargo fmton modified files - ✅ Always: Verify CI passes after pushing
Unit tests (#[test]): Logic validation in src/*/tests.rs
Comprehensive tests (src/tests_comprehensive.rs): Edge cases and coverage
Benchmarks (benches/): Performance regression testing
Doc tests: Examples in /// doc comments
Example: cargo test test_mono_neg_forward -- --nocapture
Target: >85% code coverage (currently ~87%)
# Generate coverage report
cargo tarpaulin --lib --out Stdout
# Generate HTML report
cargo tarpaulin --lib --out Html