```ts
export function admitBytes(perKey: number, total: number, span: number, entries: (string | number)[][]): string[] {
  if (!Number.isInteger(perKey) || perKey <= 0) throw new Error("perKey must be a positive integer");
  if (!Number.isInteger(total) || total <= 0) throw new Error("total must be a positive integer");
  if (!Number.isInteger(span) || span <= 0) throw new Error("span must be a positive integer");

  const result: string[] = [];
  const keyVolumes: Map<string, number[]> = new Map();
  let currentTotalVolume = 0;

  for (const entry of entries) {
    if (entry.length !== 3) throw new Error("Each entry must have exactly three elements");
    const [time, key, size] = entry;
    if (!Number.isInteger(time) || time < 0) throw new Error("Time must be a non-negative integer");
    if (typeof key !== "string" || key.length === 0) throw new Error("Key must be a non-empty string");
    if (!Number.isInteger(size) || size <= 0) throw new Error("Size must be a positive integer");

    // Ensure times are not running backwards
    if (result.length > 0 && time < entries[result.length - 1][0]) {
      throw new Error("Times must not run backwards");
    }

    // Update key volumes and total volume by removing expired entries
    const currentTime = time;
    for (const [k, volumes] of keyVolumes.entries()) {
      while (volumes.length > 0 && volumes[0][0] <= currentTime - span) {
        currentTotalVolume -= volumes[0][1];
        volumes.shift();
      }
    }

    // Calculate the volume for the current key
    const keyVolume = keyVolumes.get(key)?.reduce((acc, [t, s]) => acc + s, 0) || 0;

    // Determine if the entry can be carried
    if (keyVolume + size <= perKey && currentTotalVolume + size <= total) {
      result.push("pass");
      currentTotalVolume += size;
      keyVolumes.set(key, [...(keyVolumes.get(key) || []), [currentTime, size]]);
    } else {
      result.push("drop");
    }
  }

  return result;
}
```