mustflow_doc: skill.rust-code-change locale: en canonical: true revision: 4 lifecycle: mustflow-owned authority: procedure name: rust-code-change description: Apply this skill when Rust source, Cargo metadata, features, traits, errors, ownership, async runtime, unsafe code, tests, examples, benchmarks, release profiles, MSRV, toolchain declarations, standard-library APIs, or public crate APIs are created or changed. metadata: mustflow_schema: "1" mustflow_kind: procedure pack_id: mustflow.core skill_id: mustflow.core.rust-code-change command_intents: - changes_status - changes_diff_summary - lint - build - test_related - test - docs_validate_fast - mustflow_check
Rust Code Change
Purpose
Preserve Rust ownership, error, trait, feature, async runtime, unsafe, and public crate boundaries while making a focused change. A Rust change is successful only when it clarifies ownership and contracts, not when it merely silences the borrow checker.
Rust's compiler feedback can be especially useful for AI-assisted work because it rejects many invalid states with concrete errors. That benefit has a real cost: compile time, target-directory growth, native toolchain setup, release-profile slowness, and smoke-target selection must be managed instead of treated as incidental.
Use When
.rs,Cargo.toml,Cargo.lock, workspace config, feature flags, public exports, traits, error types, tests, examples, benches, FFI, async runtime, or unsafe code change.- The task touches ownership, borrowing, lifetimes,
Clone,Arc,Mutex,unwrap, or public crate compatibility. - The task introduces or reviews Rust-version-gated APIs or language behavior such as
let else, let chains, matchif letguards,cfg_select!,assert_matches!,core::range,Vec::push_mut,HashMap::get_disjoint_mut,Option::take_if,LazyLock,OnceLock,workspace.lints,rust-version, Rust 2024 lints, or release-profile tuning.
Do Not Use When
- Rust files are read-only context and no Rust surface changes.
- A generated Rust file should be regenerated by a declared command rather than edited.
Required Inputs
Cargo.toml, workspace manifests, lockfile policy, toolchain config, rustfmt, clippy, feature flags, docs.rs metadata, optional dependencies, build profiles, target directory or cache policy, and CI hints.- Relevant
src/lib.rs,src/main.rs, modules, public re-exports, tests, examples, and docs examples. - Existing error handling convention and async runtime.
- Public crate status, minimum supported Rust version, feature support policy, and downstream compatibility expectations when available.
rust-version, edition,rust-toolchain.toml, CI toolchain matrix, target triples, Cargo resolver, workspace inheritance policy, and whether newer standard-library APIs require a raised MSRV.- Host and build-loop constraints: OS, shell, native toolchain prerequisites, VM or remote-builder use, release profile, LTO, workspace size, disk budget, and configured smoke or focused-check intents.
- Configured verification intents.
Preconditions
- Determine whether the change affects ownership flow, public API, feature gates, optional dependencies, error contract, async runtime, or unsafe invariants.
- Read local patterns before adding traits, lifetimes, clones, locks, boxed errors, feature bounds, or
Send + Sync + 'staticconstraints. - Treat
clone,Arc<Mutex<_>>, explicit lifetimes,'static,Box<dyn Error>,unwrap, feature changes, andunsafeas suspicious until their contract impact is justified. - Identify the intended edit-check-test loop before choosing a broad build. Treat whole-workspace checks, release builds, fat LTO, cross-compiles, and sanitizer-style runs as expensive evidence unless the command contract declares them as the normal focused path.
- If a Rust release, "latest stable Rust", standard-library feature, Cargo behavior, edition behavior, lint default, or toolchain-support claim is written durably, use
version-freshness-checkand official Rust sources before relying on memory or pasted notes.
Allowed Edits
- Prefer truthful ownership and borrowing over broad cloning.
- Follow the crate's existing application-versus-library error convention.
- Keep feature-gated code and public re-exports synchronized.
- Touch unsafe code only with explicit invariants preserved in nearby comments.
- Add feature, async, or unsafe verification notes when configured command intents are missing.
- Keep build cache cleanup, remote compilation, VM escape hatches, and native toolchain repair as explicit environment or manual maintenance decisions. Do not hide them inside ordinary code fixes or verification.
Procedure
- Read Cargo metadata, features, optional dependencies, docs.rs metadata, toolchain config, build profiles, public exports, relevant modules, and tests.
- Classify the change as ownership, API, error, feature, async, unsafe, dependency, or test-only.
- Model the build loop before broad edits:
- identify the smallest package, crate, feature set, smoke target, or test that covers the risk;
- check whether
target/or an equivalent cache may grow enough to affect local disk budget; - treat cleaning build caches as a manual maintenance tradeoff because it can turn later compile checks into cold, expensive builds;
- on Windows native targets, distinguish ordinary shells from developer toolchain shells when MSVC, SDK, linker, or environment setup is required;
- treat VM builds, remote builders, release profiles, fat LTO, and whole-workspace checks as environment and verification choices that must be reported when they dominate iteration cost.
- Determine the Rust version contract before using newer syntax or standard-library APIs:
- treat
rust-version, edition,rust-toolchain.toml, CI matrix, docs.rs metadata, and downstream compatibility notes as the MSRV evidence ledger; - do not use 1.95+ APIs such as
cfg_select!, matchif letguards, orVec::push_mut, or 1.96+ APIs such asassert_matches!andcore::range, unless the declared MSRV and toolchain path support them; - keep experimental, nightly-only, target-specific, or edition-specific behavior behind explicit gates or fallbacks instead of calling it general Rust advice.
- treat
- Prefer flatter control flow when the MSRV supports it: use
let elsefor early validation, let chains for related optional/result guards, and matchif letguards for state-machine refinements. Remember that guard patterns do not satisfy match exhaustiveness; keep the fallback arm meaningful. - In tests, prefer
assert_matches!overassert!(matches!(...))when the MSRV supports it and the failed value has usefulDebugoutput. Import it explicitly fromstdorcore; do not assume it is in the prelude. - Resolve ownership problems in this order: identify the real owner, shrink borrow scopes, fix function signatures to accept references or slices when ownership is unnecessary, distinguish transfer from sharing, then consider clone or shared ownership only when the semantics require it.
- Before adding
clone, verify it is a cheap handle clone such asArc,Rc, orBytes, a small intentional value clone, or a true independent ownership split. Reject large collection clones, loop clones, clone-then-borrow code, and whole-state clones made only to satisfyspawn. - Before adding
Arc<Mutex<_>>, verify multiple owners truly need shared mutable state. For read-mostly snapshots, prefer ownership-preserving choices such asArc::make_mut, immutable swaps, or explicit reload boundaries. Keep critical sections short, document lock order when relevant, and do not hold a lock guard across.await, I/O, callbacks, or user code. - Choose initialization primitives by input and failure semantics: use
LazyLockfor no-argument static lazy values that may poison permanently on panic, andOnceLockwhen boot-time or test-time code supplies the value or panic poisoning must not become the recovery policy. - Avoid hidden allocation when cheaper type contracts fit: use
Cow<'_, str>or borrowed slices for mostly-borrowed results, queryHashMap<String, V>with&strwhenBorrowsupports it, useOption::take,take_if, oras_slicefor state transitions and 0-or-1 iteration, and useControlFlow,try_for_each, ortry_foldwhen visitor or iterator APIs need explicit short-circuiting. - Treat collection and string capacity as part of performance correctness. Use
with_capacity,reserve,spare_capacity_mut, orpush_mutonly when the safety and MSRV contract are clear; keepset_leninside a small proven unsafe boundary; avoid repeatedString::insertor front insertion loops that create quadratic movement. - Use explicit lifetimes only to describe real borrow relationships. Do not add
'staticorT: 'staticto public APIs merely because an internal task boundary requires it. - Use concrete error enums for library APIs when callers need to classify failures. Keep
Box<dyn Error>mostly to binaries, examples, tests, prototypes, or explicitly opaque error policies. - Avoid
unwrap, vagueexpect, and unboundedpanic!in production paths. They are allowed only for tests, examples, startup policy, panic-boundary adapters, or invariants already proven by nearby code. - Review public API shape before adding
impl Trait,Deref, or trait/lifetime machinery:
- argument-position
impl Traitremoves caller turbofish control and can be a public breaking change when converted from named generics; - return-position
impl Traithides one concrete type, so divergent iterator or future branches need an enum, boxed trait object, or different API boundary; - implement
Derefonly for pointer-like wrappers, not domain inheritance or method forwarding; - use GATs for borrowing iterator/view traits when they remove a real allocation or boxed lifetime escape, not as decorative complexity.
- If feature flags or Cargo workspace metadata change, treat default features, no-default builds, all-features builds, optional dependency implicit features, resolver behavior, target-specific dependencies,
workspace.package,workspace.dependencies,workspace.lints, public re-exports, docs examples, and feature-gated trait impls as compatibility surfaces. Features should be additive, andresolver = "2"or a newer resolver decision must match the crate's edition/MSRV policy. - Treat public re-exports, public dependency types, generic bounds, trait item sets, error enum variants,
#[non_exhaustive], and MSRV as public API. Tightened bounds, added required trait methods, removed re-exports, changed error variants, or raisedrust-versionrequire compatibility review. - Do not mix async runtimes. A Tokio crate should not casually gain
async-stdor runtime-specific APIs in library core. Do not call blocking I/O or CPU-heavy work in async paths without an established boundary such as async-native APIs, a blocking pool, or a dedicated worker. - For async spawning, avoid leaking internal
Send + Sync + 'staticrequirements into public APIs. Prefer owned task state, smaller spawn boundaries, local task structures, or caller-owned runtime decisions. - Touch
unsafeonly when a safe design cannot express the required behavior. Every unsafe block needs a nearbySAFETY:explanation; every publicunsafe fnneeds# Safetydocs. In Rust 2024 or whenunsafe_op_in_unsafe_fnis enabled, unsafe operations insideunsafe fnstill need explicit unsafe blocks. Keep unsafe scopes small and wrap them in safe abstractions only when callers have no hidden safety obligations. - For FFI, keep Rust ABI types out of C boundaries. Use explicit ownership,
#[repr(C)]where required, raw pointer plus length pairs,CStr/CString, RAII wrappers, null handling, panic boundaries, and documented thread-safety evidence before manualSendorSync. - Review release profiles when the task changes binary delivery, CLI startup, embedded, wasm, or performance behavior. Treat
opt-level, LTO,panic,codegen-units, andstripas product tradeoffs that must be measured or reported, not decorative Cargo knobs. - Calibrate performance claims. Do not claim Rust made a system faster from compile success, empty-database timings, warm-cache microbenchmarks, local-only runs, or debug versus release confusion. Require representative data size, concurrency, target hardware, profile, and measurement method before reporting speed claims.
- Choose configured verification intents that cover format, lint, build, tests, feature combinations, docs, public API, unsafe, FFI, smoke targets, package artifact, and release-profile risk when available.
Review Rejection Criteria
Reject or revise the patch when any of these appear without strong local justification:
- New large
clone()calls, clone-then-borrow code, loop clones, or state clones used only to appease ownership errors. - New
Arc<Mutex<AppState>>-style shared bags, locks held across.await, or async I/O resources shared mainly by mutex. - New Rust 1.95+ or 1.96+ API usage without MSRV,
rust-version, edition, toolchain, CI, or fallback evidence. - New
LazyLockinitialization for recoverable runtime configuration where permanent panic poisoning would be the wrong failure policy. - New
spare_capacity_mutplusset_lenwithout a narrow, proven initialization invariant. - New public
impl Trait,Deref, GAT, workspace resolver, feature, orrust-versionchange without public API and compatibility review. - New public
'static,Send, orSyncbounds that exist only because an internal task was spawned. - New public
Box<dyn Error>in a library where callers need typed failures. - New production
unwrapor vagueexpecton I/O, parse, environment, network, FFI, lock, or user input paths. - New unbounded
panic!paths, index assumptions, or unchecked slicing in production paths without a documented invariant or panic boundary. - Feature changes that remove APIs, change type meaning, rename features, expose internal optional dependency names, or fail default/no-default/all-features reasoning.
- Public dependency types, re-exports, trait bounds, trait methods, or error enum variants changed without semver review.
- Async runtime mixing, blocking I/O in async paths, or runtime ownership moved into a library core without a clear boundary.
- Unsafe blocks without
SAFETY:comments, unsafe functions without# Safety, undocumented manualSend/Sync, or FFI that exposes Rust layout types across C ABI. - Whole-workspace, release, or fat-LTO verification treated as the normal agent loop when a smaller configured smoke or related target should exist.
- Performance superiority claims based on non-representative workloads, empty databases, local-only timings, or unspecified build profile.
Postconditions
- Ownership changes are intentional, not compiler appeasement.
- Rust-version-gated syntax, standard-library APIs, Cargo behavior, and lint assumptions match the declared MSRV or have explicit fallbacks.
- Public API, features, optional dependencies, and error contracts are synchronized.
- Async runtime ownership is preserved and blocking work is isolated.
- Unsafe,
unsafe_op_in_unsafe_fn, and FFI invariants are preserved or no unsafe code was touched. - Allocation, initialization, Cargo workspace, and release-profile choices are intentional and reported when they affect public or delivery behavior.
- Build-loop cost, target/cache impact, smoke-target coverage, and native toolchain prerequisites are handled or reported.
- Missing feature, semver, docs, unsafe, FFI, smoke, package, or performance verification is reported.
Verification
Use configured oneshot command intents when available:
lintbuildtest_relatedtestdocs_validate_fastmustflow_check
Report whether configured feature-combination, documentation, semver, Miri, sanitizer, smoke-target, package artifact, release-profile, and downstream-style verification exists when those surfaces change.
When configured intents exist for these risks, prefer coverage equivalent to:
- formatting and linting
- workspace checks and tests
- focused smoke targets for the changed crate, command, API route, or engine invariant
- default, no-default, all-features, and relevant feature combinations
- doctests and docs build for public crates
- public API or semver compatibility checks for published crates
- Miri or sanitizer-style checks for unsafe, raw pointer, FFI, or manual concurrency primitives
- representative benchmark or load checks when performance claims are introduced
Failure Handling
- If borrow-checker fixes produce broad clones or locks, revisit ownership boundaries before proceeding.
- If feature-gated code cannot be verified, report the specific unverified feature surface.
- If public API compatibility cannot be verified, report the exact exported symbols, trait bounds, feature gates, or errors at risk.
- If async runtime or blocking boundaries are unclear, stop that part and inspect the runtime ownership before editing further.
- If unsafe invariants are unclear, stop that part and request or inspect stronger evidence.
- If the build loop is too expensive, reduce the verification scope to the configured related or smoke intent when available, or report the missing command contract instead of running broad raw builds.
- If host toolchain setup is missing, report the prerequisite rather than running global installer, repair, or shell-environment commands.
- If performance claims lack representative evidence, downgrade or remove the claim.
Output Format
- Boundary checked
- Build-loop, cache, smoke target, and toolchain notes
- Ownership, feature, async, or unsafe impact
- Public API or error impact
- Files changed
- Command intents run
- Skipped checks and reasons
- Remaining Rust risk