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

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

  charges.forEach(([chargeId, bucketName, amount]) => {
    if (!caps[bucketName]) {
      result.refused.push([chargeId, 'unknown']);
      return;
    }

    const [allowance, singleCharge] = caps[bucketName];

    if (amount > singleCharge) {
      result.refused.push([chargeId, 'single']);
      return;
    }

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

    result.left[bucketName] = allowance - amount;
  });

  return result;
}
```