R01BREAKINGfunction

Parameter 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)
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), OK

How 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