```ts
/**
 * Runs a patrol bot in a corridor and clamps moves according to wall collisions.
 * @param width - The width of the corridor (must be a positive integer).
 * @param start - The starting position of the bot (must be an integer within the corridor bounds).
 * @param moves - An array of non-zero integers representing the moves to apply.
 * @returns An object containing the final position, number of bumps, and visited cells.
 */
export function runPatrol(width: number, start: number, moves: number[]): Record<string, number> {
    if (!Number.isInteger(width) || width <= 0) {
        throw new Error("Width must be a positive integer.");
    }
    if (!Number.isInteger(start) || start < 0 || start >= width) {
        throw new Error("Start position must be an integer within the corridor bounds.");
    }
    if (!Array.isArray(moves)) {
        throw new Error("Moves must be an array of numbers.");
    }

    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("Move must be a non-zero integer.");
        }
        [position, bump] = clampMove(position, move, width);
        bumps += bump;
        visited.add(position);
    }

    return { position, bumps, visited: visited.size };
}

/**
 * Clamps a move to the corridor bounds and returns whether it hit a wall.
 * @param position - The current position of the bot.
 * @param delta - The move to apply (can be positive or negative).
 * @param width - The width of the corridor.
 * @returns A tuple with the new position and a boolean indicating if a bump occurred.
 */
export function clampMove(position: number, delta: number, width: number): [number, boolean] {
    const newPosition = position + delta;
    const bumped = newPosition < 0 || newPosition >= width;
    return [bumped ? (delta > 0 ? width - 1 : 0) : newPosition, bumped];
}
```