- Ownership forms a tree/DAG, never a cycle. One clear owner per value.
- For references between values (or any logical cycle): use
slotmapkeys, orVecindices only if nothing is ever removed. Do NOT default toRc<RefCell<T>>; treatRc/Arc<Mutex<T>>as last resorts after trying ownership + keys. - Prefer owned fields over borrowed (
&'a T) fields. If a struct sprouts a lifetime parameter, reconsider — it usually wants owned data or a key. Legitimate exception: a short-lived,Copy, read-only view struct passed into one call and never stored (e.g.NoteRowindb.rs) — borrowing there avoids a needless clone; keep it, and say so in the doc-comment. - Never silence the borrow checker with a reflexive
.clone(). Diagnose ownership first: should this be a key instead of a reference? - No self-referential structs in safe Rust; restructure with indices.
- No
.unwrap()/.expect()in production paths; handle viamatch,if let, or?. This holds even for an invariant you believe can't fail (e.g.strip_prefixon a path you just walked) — degrade gracefully (skip it) rather than panic. - When stuck, ask: "Who owns this, and can the relationship be an ID instead of a pointer?"
- Errors: reach for
thiserrortyped enums wherever error variants get matched on — every library, and any binary that does too: the CLI maps variants to user-facing messages inuser_message, soCliErroris athiserrorenum, notanyhow(which erases the type and would forcedowncast_ref). Useanyhowonly where errors are merely propagated and printed. Never hand-rollFrom/Displayimpls —#[from]and#[error("…")]generate them. - Signatures: accept
&strnot&String,&[T]not&Vec<T>. Return owned types and let callers borrow. - Prefer iterator chains over manual index loops (
for x in &items, notfor i in 0..items.len()). - Do NOT introduce
async/tokio, generics, traits, or macros until there's a concrete need. No speculative abstraction. unsaferequires an explicit// SAFETY:comment stating the invariant that makes it sound (seedb.rs'ssqlite-vecregistration andmodel.rs's weights mmap); otherwise disallowed.- Derive
Debugon public data types (andClone/PartialEqwhere it makes sense). - Keep modules small and domain-named; document public items with
///comments stating intent, not mechanics.