```ts
/**
 * Assigns berths based on the given requests and constraints.
 * @param berths - List of available berths with id and size.
 * @param quota - Mapping of owners to their maximum number of berths they can hold.
 * @param requests - List of request objects with op, boat, owner, and optionally size.
 * @returns A list of result strings for each request.
 */
export function assignBerths(
  berths: Array<{ id: string; size: number }>,
  quota: Record<string, number>,
  requests: Array<Record<string, unknown>>
): string[] {
  const results: string[] = [];
  const occupiedBerths: Record<string, { berthId: string; owner: string }> = {};
  const berthAvailability: Record<string, boolean> = {};

  // Check for duplicate berth ids
  if (new Set(berths.map((b) => b.id)).size !== berths.length) {
    throw new Error("Duplicate berth ids found");
  }

  // Initialize berth availability
  berths.forEach((b) => {
    berthAvailability[b.id] = true;
  });

  for (const request of requests) {
    const { op, boat, owner, size } = request;

    if (op === "dock") {
      if (occupiedBerths[boat as string]) {
        results.push("rejected:already_docked");
        continue;
      }

      const ownerQuota = quota[owner as string] ?? Infinity;
      const ownedBerthCount = Object.values(occupiedBerths).filter(
        (b) => b.owner === owner
      ).length;

      if (ownedBerthCount >= ownerQuota) {
        results.push("rejected:over_quota");
        continue;
      }

      const availableBerth = berths.find((b) => berthAvailability[b.id] && b.size >= size as number);

      if (!availableBerth) {
        results.push("rejected:no_berth");
        continue;
      }

      occupiedBerths[boat as string] = { berthId: availableBerth.id, owner: owner as string };
      berthAvailability[availableBerth.id] = false;
      results.push(availableBerth.id);
    } else if (op === "leave") {
      if (!occupiedBerths[boat as string]) {
        results.push("rejected:not_docked");
        continue;
      }

      const { berthId } = occupiedBerths[boat as string];
      delete occupiedBerths[boat as string];
      berthAvailability[berthId] = true;
      results.push("left");
    } else {
      throw new Error(`Invalid operation: ${op}`);
    }
  }

  return results;
}
```