Skip to content
Documentation GitHub
Workflow Issues

Derive Copy Cross-Agent Ripple: Adding Copy to a Shared Type Breaks Downstream Clippy

Derive Copy Cross-Agent Ripple

Problem

When an agent adds #[derive(Copy)] to a shared type, callers in files outside that agent’s ownership get clone_on_copy clippy warnings. Each agent’s own clippy passes (they only check their crate), but the workspace-wide clippy at the wave gate fails.

Symptoms:

  • Agent reports “clippy clean” for its crate
  • Wave gate cargo clippy --workspace -- -D warnings fails
  • Errors are in files no agent owns (e.g., framework layer calling an application layer type)

Root Cause

Adding Copy to a type is a widening change — it’s backward compatible at the type level, but clippy treats .clone() on a Copy type as a lint error (clone_on_copy). The agent making the change only removes .clone() calls in files it owns, missing callers in other crates/layers.

In this case:

  • Agent 1 (application layer) added Copy to SyncStatus and removed .clone() in sync_engine.rs
  • Framework layer files sync.rs and commands/sync.rs also called .status().clone() — not owned by any agent
  • Both agents passed their own cargo clippy -p <crate>, but workspace clippy failed

Solution

At the Wave Gate

Fix the downstream .clone()*dereference calls in the leader context:

// Before: clippy error after Copy was added
let prev_status = engine.lock().await.status().clone();
// After: dereference instead of clone
let prev_status = *engine.lock().await.status();

Prevention: Plan for Cross-Crate Ripple

When planning a derive(Copy) addition in an agent’s scope:

  1. Grep for .clone() on the type across the workspace before assigning the task
  2. Assign all affected files to the same agent, OR
  3. Document the expected wave-gate fixup in the plan so the leader knows to handle it
  4. Alternative: Have the agent run cargo clippy --workspace instead of per-crate clippy

Checklist for Derive Changes

DeriveRipple RiskWhat to Check
CopyHigh — clone_on_copygrep -r "\.clone()" on the type
PartialEqLowUsually additive
DefaultMediumCallers using Type { field: val, ..Default::default() }
Serialize/DeserializeLowUsually additive

Implementation Notes

  • The fix is always trivial (.clone()* dereference), but finding all locations requires workspace-wide search
  • This is a special case of the general pattern: trait/derive changes in shared types have workspace-wide blast radius
  • Per-crate clippy (cargo clippy -p <crate>) does NOT catch cross-crate lint issues

First Encountered

2026-02-22 — Code audit remediation. Agent “foundation-traits” added Copy to SyncStatus (P3-1). Wave 1 gate clippy failed with 3 clone_on_copy errors in apps/desktop/src-tauri/src/sync.rs and commands/sync.rs. Fixed in leader context (commit 4ee114c).

Was this page helpful?