```ts
export function gradeContainment(
  source: string[],
  draft: string[],
  span: number,
): number {
  if (!Array.isArray(source) || !Array.isArray(draft)) {
    throw new Error("Both source and draft must be arrays.");
  }
  if (span <= 0 || !Number.isInteger(span)) {
    throw new Error("Span must be a positive whole number.");
  }
  if (source.some(word => typeof word !== "string" || word.trim() === "")) {
    throw new Error("All elements in source must be non-empty strings.");
  }
  if (draft.some(word => typeof word !== "string" || word.trim() === "")) {
    throw new Error("All elements in draft must be non-empty strings.");
  }
  if (draft.length < span) {
    throw new Error("Draft must contain at least as many words as the span.");
  }

  const tally: Record<string, number> = {};
  for (let i = 0; i <= source.length - span; i++) {
    const stretch = source.slice(i, i + span).join(" ");
    tally[stretch] = (tally[stretch] || 0) + 1;
  }

  let matched = 0;
  let total = 0;
  for (let i = 0; i <= draft.length - span; i++) {
    const stretch = draft.slice(i, i + span).join(" ");
    if (tally[stretch] > 0) {
      matched += 1;
      tally[stretch] -= 1;
    }
    total += 1;
  }

  return Math.floor((matched / total) * 1000);
}
```