```typescript
export function applyCharges(caps: Record<string, [number, number]>, charges: [string, string, number][]): { left: Record<string, number>; refused: [string, string][] } {
  if (charges.some(([_, bucket, amount]) => typeof amount !== 'number' || amount <= 0)) {
    throw new Error('Amount must be a positive whole number');
  }

  const left: Record<string, number> = {};
  const refused: [string, string][] = [];

  for (const [chargeId, bucket, amount] of charges) {
    if (!caps[bucket]) {
      refused.push([chargeId, 'unknown']);
      continue;
    }

    const [allowance, maxCharge] = caps[bucket];

    if (amount > maxCharge) {
      refused.push([chargeId, 'single']);
      continue;
    }

    if (amount > allowance) {
      refused.push([chargeId, 'cap']);
      continue;
    }

    left[bucket] = allowance - amount;
  }

  return { left, refused };
}
```