```ts
export function routeLogRecords(
  rules: Array<Record<string, unknown>>,
  records: Array<Record<string, unknown>>,
  spare: string
): Array<Record<string, unknown>> {
  const validLevels = ["trace", "debug", "info", "warn", "error", "fatal"];

  if (!Array.isArray(rules) || !Array.isArray(records)) {
    throw new Error("Rules and records must be arrays.");
  }

  rules.forEach((rule, index) => {
    if (typeof rule !== "object" || rule === null) {
      throw new Error(`Rule at index ${index} is not a valid object.`);
    }
    const { sink, least, tag, stop } = rule;
    if (typeof sink !== "string" || typeof spare !== "string") {
      throw new Error("Sink and spare must be non-empty strings.");
    }
    if (!validLevels.includes(least as string)) {
      throw new Error(`Invalid level in rule at index ${index}.`);
    }
    if (typeof tag !== "string") {
      throw new Error(`Invalid tag in rule at index ${index}.`);
    }
    if (stop !== true && stop !== false) {
      throw new Error(`Stop must be a boolean in rule at index ${index}.`);
    }
  });

  records.forEach((record, index) => {
    if (typeof record !== "object" || record === null) {
      throw new Error(`Record at index ${index} is not a valid object.`);
    }
    const { level, tag } = record;
    if (!validLevels.includes(level as string)) {
      throw new Error(`Invalid level in record at index ${index}.`);
    }
    if (typeof tag !== "string") {
      throw new Error(`Invalid tag in record at index ${index}.`);
    }
  });

  return records.map((record, index) => {
    const sinks: string[] = [];
    for (const rule of rules) {
      const { sink, least, tag: ruleTag, stop } = rule;
      if (
        validLevels.indexOf(level as string) >= validLevels.indexOf(least as string) &&
        (ruleTag === "" || ruleTag === record.tag)
      ) {
        if (!sinks.includes(sink as string)) {
          sinks.push(sink as string);
        }
        if (stop) {
          break;
        }
      }
    }
    if (sinks.length === 0) {
      sinks.push(spare);
    }
    return { at: index, sinks };
  });
}
```