R01BREAKINGfunctionParameter Removed
Flags when a parameter (required or optional) is entirely removed from a function signature. Every caller that passes this argument will break.
Applies to
TypeScriptPythonGoJavaRust
Why it matters
When a parameter is removed from a function, every call site that passes that argument will either:
• Fail to compile in statically typed languages (TypeScript strict mode, Java, Rust, Go)
• Silently shift argument positions in dynamically typed languages (JavaScript, Python positional args)
• Fail to compile in statically typed languages (TypeScript strict mode, Java, Rust, Go)
• Silently shift argument positions in dynamically typed languages (JavaScript, Python positional args)
The second case is especially dangerous — code appears to work but receives the wrong values.
Example
Before (v1.0.0)
// payments.ts — v1.0.0
export function processPayment(
amount: number,
currency: string,
metadata?: Record<string, string>
): PaymentResult {
return gateway.charge(amount, currency, metadata);
}After (v2.0.0)
// payments.ts — v2.0.0 (BREAKING)
export function processPayment(
amount: number,
metadata?: Record<string, string>
): PaymentResult {
// currency was removed — now defaults to USD internally
return gateway.charge(amount, 'USD', metadata);
}What you see in the terminal
$ npx dg compare main
[BREAKING] processPayment (signature_change)
src/api/payments.ts:42
Parameter 'currency' was removed. Callers providing this argument will fail.
Affected call sites (3):
X src/checkout/handler.ts:18 -- provides 3 arg(s), needs max 2
X src/invoices/gen.ts:31 -- provides 3 arg(s), needs max 2
. src/subscriptions/renew.ts:9 -- 2 arg(s), OKHow detection works
The classifier iterates through the old signature's parameter list and checks if each parameter name still exists in the new signature. If a parameter from the old signature cannot be found in the new signature by name, the rule fires.
for (const oldParam of oldSig.params) {
const stillExists = newSig.params.some(
newParam => newParam.name === oldParam.name
);
if (!stillExists) {
// BREAKING: parameter was removed
}
}Real-world scenario
A payments team removes the `currency` parameter from `processPayment()` because they've decided to default to USD. The checkout handler still passes three arguments: `processPayment(100, 'EUR', {})`. After the change, `'EUR'` lands in the `metadata` parameter position, and the function silently processes a USD payment with metadata as a string instead of an object.
Edge cases
- Removing an optional parameter is still breaking — callers may be providing it
- Renaming a parameter counts as removal of the old + addition of the new
- Destructured parameters are matched by their top-level name, not nested keys