```ts
export function runPatrol(width: number, start: number, moves: number[]): Record<string, number> {
  if (!Number.isInteger(width) || width <= 0) {
    throw new Error('Invalid width');
  }
  if (!Number.isInteger(start) || start < 0 || start >= width) {
    throw new Error('Invalid start position');
  }
  if (!Array.isArray(moves)) {
    throw new Error('Invalid moves argument');
  }

  let position = start;
  let bumps = 0;
  const visited = new Set<number>();

  for (const move of moves) {
    if (!Number.isInteger(move) || move === 0) {
      throw new Error('Invalid move');
    }
    [position, bumps] = clampMove(position, move, width);
    visited.add(position);
  }

  visited.delete(start); // Remove start position if it's the only one visited
  return { position, bumps, visited: visited.size };
}

export function clampMove(position: number, delta: number, width: number): [number, boolean] {
  let newPosition = position + delta;
  let bumped = false;

  if (newPosition < 0) {
    newPosition = 0;
    bumped = true;
  } else if (newPosition >= width) {
    newPosition = width - 1;
    bumped = true;
  }

  return [newPosition, bumped];
}
```