```ts
export function replayEnvelopes(envelopes: Array<{ name: string; monthly: number; cap: number }>, months: Array<Array<[string, number]>>): { balances: Array<[string, number]>; forfeited: number } {
  // Validate envelopes
  const envelopeMap = new Map<string, { monthly: number; cap: number; balance: number; totalForfeited: number }>();
  for (const envelope of envelopes) {
    if (!envelope.name || typeof envelope.name !== 'string') {
      throw new Error('Envelope name must be a non-empty string');
    }
    if (envelopeMap.has(envelope.name)) {
      throw new Error('Duplicate envelope name');
    }
    if (typeof envelope.monthly !== 'number' || envelope.monthly < 0) {
      throw new Error('Monthly amount must be a non-negative integer');
    }
    if (typeof envelope.cap !== 'number' || envelope.cap < 0) {
      throw new Error('Cap must be a non-negative integer');
    }
    envelopeMap.set(envelope.name, { monthly: envelope.monthly, cap: envelope.cap, balance: 0, totalForfeited: 0 });
  }

  // Process each month
  for (const outlays of months) {
    // Step 1: Apply monthly deposits
    for (const [name] of outlays) {
      const envelope = envelopeMap.get(name);
      if (!envelope) {
        throw new Error('Outlay names an unknown envelope');
      }
      envelope.balance += envelope.monthly;
    }

    // Step 2: Apply outlays
    for (const [name, amount] of outlays) {
      const envelope = envelopeMap.get(name);
      if (!envelope) {
        throw new Error('Outlay names an unknown envelope');
      }
      if (typeof amount !== 'number' || amount <= 0) {
        throw new Error('Outlay amount must be a positive integer');
      }
      envelope.balance -= amount;
    }

    // Step 3: Apply caps and calculate forfeited amounts
    for (const [name] of outlays) {
      const envelope = envelopeMap.get(name);
      if (!envelope) {
        throw new Error('Outlay names an unknown envelope');
      }
      if (envelope.balance > envelope.cap) {
        envelope.totalForfeited += envelope.balance - envelope.cap;
        envelope.balance = envelope.cap;
      }
    }
  }

  // Prepare the result
  const balances: Array<[string, number]> = [];
  let forfeited = 0;
  for (const [name, { balance, totalForfeited }] of envelopeMap.entries()) {
    balances.push([name, balance]);
    forfeited += totalForfeited;
  }

  return { balances, forfeited };
}
```