```ts
export function planWarmup(brief: Record<string, unknown>): Record<string, unknown> {
  if (typeof brief !== 'object' || brief === null) {
    throw new Error('Invalid argument');
  }

  const { budget, slots, caps, items } = brief;

  if (
    typeof budget !== 'number' ||
    !Number.isInteger(budget) ||
    budget < 0
  ) {
    throw new Error('Invalid budget');
  }

  if (
    typeof slots !== 'number' ||
    !Number.isInteger(slots) ||
    slots <= 0
  ) {
    throw new Error('Invalid slots');
  }

  if (typeof caps !== 'object' || caps === null) {
    throw new Error('Invalid caps');
  }

  if (!Array.isArray(items)) {
    throw new Error('Invalid items');
  }

  const familyCaps = Object.fromEntries(
    Object.entries(caps).map(([family, cap]) => {
      if (
        typeof family !== 'string' ||
        family.trim() === '' ||
        typeof cap !== 'number' ||
        !Number.isInteger(cap) ||
        cap < 0
      ) {
        throw new Error('Invalid caps');
      }
      return [family, cap];
    })
  );

  const itemEntries = items.map((item, index) => {
    if (typeof item !== 'object' || item === null) {
      throw new Error('Invalid item');
    }

    const { name, bytes, weight, family } = item as Record<string, unknown>;

    if (
      typeof name !== 'string' ||
      name.trim() === '' ||
      typeof bytes !== 'number' ||
      !Number.isInteger(bytes) ||
      bytes <= 0 ||
      typeof weight !== 'number' ||
      !Number.isInteger(weight) ||
      weight < 0 ||
      typeof family !== 'string' ||
      family.trim() === ''
    ) {
      throw new Error('Invalid item');
    }

    if (!familyCaps.hasOwnProperty(family)) {
      throw new Error('Invalid item');
    }

    return { name, bytes, weight, family };
  });

  const uniqueNames = new Set(itemEntries.map(item => item.name));
  if (uniqueNames.size !== items.length) {
    throw new Error('Duplicate item names');
  }

  itemEntries.sort((a, b) => {
    if (b.weight !== a.weight) {
      return b.weight - a.weight;
    }
    if (a.bytes !== b.bytes) {
      return a.bytes - b.bytes;
    }
    return a.name.localeCompare(b.name);
  });

  const loaded: string[] = [];
  const turned: { name: string; why: string }[] = [];
  let remainingSlots = slots;
  const familyUsage: Record<string, number> = {};

  for (const item of itemEntries) {
    if (remainingSlots === 0) {
      turned.push({ name: item.name, why: 'slots' });
      continue;
    }

    const familyCap = familyCaps[item.family];
    const usedByFamily = familyUsage[item.family] || 0;

    if (usedByFamily >= familyCap) {
      turned.push({ name: item.name, why: 'family' });
      continue;
    }

    if (item.bytes > budget) {
      turned.push({ name: item.name, why: 'bytes' });
      continue;
    }

    loaded.push(item.name);
    remainingSlots -= 1;
    familyUsage[item.family] = usedByFamily + 1;
    budget -= item.bytes;
  }

  return {
    loaded,
    spare: budget,
    turned,
  };
}
