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