Ripple Effect Prevention
Prevent cascading breaks when AI modifies code with dependencies.
What is the Ripple Effect?
When AI modifies a function, it might not realize other code depends on it:
// Original function
function getUserById(id: string): User {
return db.users.find(u => u.id === id);
}
// AI "improves" it to be async
async function getUserById(id: string): Promise<User> {
return await db.users.findAsync(u => u.id === id);
}
// 15 other files now break because they
// weren't updated to await the resultThis is the "ripple effect" - one change breaks many dependent files.
Preventing Ripple Effects
1. Document Dependencies
Use protection annotations to indicate what depends on a function:
/**
* @protected
* DEPENDENCIES: UserProfile, Dashboard, Settings, AdminPanel
* CALLERS: 8 files total
*/
function getUserById(id: string): User { ... }2. Ask AI About Impact
Before making changes, ask your AI assistant about dependencies:
"What files call getUserById? What would break if I change the return type?"
3. Use Protection Annotations
Mark high-dependency functions for protection:
Functions with many callers should be marked @protected or @maintainable to signal AI should be careful.
4. Request Full Updates
When a breaking change is needed, tell AI to update all callers:
"Change getUserById to async and update all callers to await the result. Check these files: - src/components/UserProfile.tsx - src/components/Dashboard.tsx - src/pages/settings.tsx ..."
Interface Contracts
Define contracts that must be maintained even if implementation changes:
/**
* @maintainable
* INTERFACE CONTRACT:
* - Input: (id: string)
* - Output: User | null (synchronous)
* - Throws: never (returns null on not found)
*
* Implementation can change, but interface must not.
*/
function getUserById(id: string): User | null {
// Free to refactor internals
}AI understands it can improve the implementation but must preserve the contract.
Prevention Strategies
Wrapper Functions
Create a stable wrapper that calls the changing implementation. Dependents use the wrapper.
Version Functions
Keep old function, create getUserByIdV2() for new behavior. Migrate callers gradually.
Type Guards
Use TypeScript to catch interface changes at compile time before they cause runtime errors.
Test Coverage
Tests catch ripple effects. Lumina can suggest running specific tests after changes.
Best Practices
- 1.Identify high-dependency functions - Search for functions called from multiple files
- 2.Document interfaces - Make contracts explicit in comments
- 3.Ask AI about impact - "What files would break if I change this?"
- 4.Review suggested changes - Check for interface modifications
- 5.Run tests after changes - Catch ripples early