# Horas posibles: a qué hora puede empezar una reserva de N horas

Laboratorio de la semana 4. Primero el pedido tal como llegó; después, lo que
respondió la administración a las preguntas de otro grupo; al final, el
template de la especificación que van a copiar en `docs/specs/horas-posibles.md`
de su copia de Kallpa.

## 1. El pedido

Mensaje de Doris Chumpitaz, de la administración del complejo:

> La página muestra hora por hora qué está libre, y eso está bien para el que
> quiere una hora. Pero el que quiere dos o tres horas tiene que ir mirando
> una por una dónde le caben, y muchos se equivocan: eligen las 20:00 para
> dos horas y el sistema les dice que no, porque a las 21:00 ya hay alguien.
> Queremos que, cuando el vecino elija cuántas horas quiere, la página le
> muestre directamente a qué horas puede empezar.
>
> Me dicen que lo primero es una función que, con las reservas de esa cancha
> para ese día, la fecha, cuántas horas quiere y la hora de ahora, diga las
> horas de inicio posibles. Después se conecta con la página.

La función va en `src/domain/possible-start-hours.ts`, con esta firma:

```ts
import type { Booking } from './booking.ts';
import type { LimaTime } from './clock.ts';

export function possibleStartHours(
  bookings: readonly Booking[],
  date: string,
  hours: number,
  now: LimaTime,
): number[];
```

`bookings` son las reservas que devuelve el sistema para esa cancha y ese día
(`BookingService.bookingsForCourt`, convertidas con `toBookingJson`), con las
canceladas incluidas. `date` es la fecha elegida (`'YYYY-MM-DD'`), `hours` la
cantidad de horas y `now` la hora de Lima (`limaTime(clock.now())`).

**Antes de seguir leyendo, hagan el paso 1 de la guía**: la lista de lo que
el pedido no dice.

## 2. Lo que respondió la administración

Otro grupo le hizo a Doris estas preguntas. Sus respuestas, con sus palabras:

- **¿Cuentan las reservas canceladas?** "No. Si una reserva se canceló, esa
  hora está libre otra vez, aunque la reserva siga apareciendo en la lista."
- **¿Y si la fecha es hoy?** "Las horas que ya empezaron no se ofrecen, igual
  que al reservar. Si son las 10:30, la de las 10:00 ya empezó. Si son las
  10:00 en punto, la de las 10:00 también: ya no se puede reservar."
- **¿En qué orden?** "De la más temprana a la más tarde, cada hora una sola
  vez. Así las vamos a mostrar."
- **¿Y si `hours` es 0, o 4, o 2.5?** "La página solo deja elegir 1, 2 o 3.
  No sé qué debería pasar si llega otra cosa. Decidan ustedes, pero
  escríbanlo."
- **¿Y si la fecha ya pasó, o es de aquí a un mes?** "Tampoco se puede
  elegir en la página: el calendario solo muestra de hoy a dos semanas.
  Lo mismo: decidan y escríbanlo."

Las reglas del complejo están en el [README de Kallpa](../../kallpa/README.md#reglas-del-negocio):
horario de 7:00 a 22:00, reservas de 1 a 3 horas seguidas, una cancha no
tiene dos reservas confirmadas que se crucen.

Las dos últimas respuestas dejan una decisión abierta: ¿la función **revisa**
esos casos (y entonces dice qué devuelve o qué lanza), o los **exige** como
precondición (y entonces quien la llama los garantiza y la función no promete
nada si no se cumplen)? Las dos opciones son válidas. Lo que no vale es no
decidir.

## 3. Template de la especificación

Copien esto en `docs/specs/horas-posibles.md` y llénenlo. Donde dice
*decidir*, escriban la decisión y el porqué en una línea.

```md
# Especificación: possibleStartHours

Autores: ...      Revisado por (otra pareja): ...      Fecha: ...

## Propósito

Una o dos frases: qué responde la función y para quién.

## Firma

(la firma en TypeScript, copiada del pedido)

## Precondiciones

Lo que quien llama tiene que garantizar. Para cada una: ¿la función la
revisa (y qué hace si no se cumple) o la exige (y no promete nada)?

- `bookings`: ...
- `date`: ... (decidir: ¿qué pasa con una fecha que ya pasó o fuera de las
  dos semanas?)
- `hours`: ... (decidir: ¿qué pasa con 0, 4 o 2.5?)
- `now`: ...

## Postcondiciones

Lo que la función garantiza si se cumplen las precondiciones. Escríbanlo de
forma que una función que devuelve siempre `[]` NO lo cumpla.

- Toda hora devuelta ...
- Toda hora que ... aparece en el resultado.
- Orden y repetidos: ...

## Invariante del que depende

Qué propiedad del sistema da por cierta la función (y qué pasaría si no
se cumple).

## Ejemplos

Al menos 6, incluidos los bordes. Hoy es lunes 9 de marzo de 2026.

| # | Reservas de la cancha ese día | date | hours | now | Resultado |
|---|---|---|---|---|---|
| 1 | ninguna | 2026-03-10 | 1 | 2026-03-09 10:30 | 7, 8, ..., 21 |
| 2 | ... | ... | ... | ... | ... |

## Lo que la función no hace

Por ejemplo: no sabe de precios, no reserva, no revisa ...

## Preguntas abiertas

Lo que todavía no está decidido y a quién hay que preguntarle.
```

## 4. El esqueleto

El paso 3 de la guía pide crear el archivo con la firma, un comentario que
resuma el contrato y este cuerpo:

```ts
throw new Error('sin implementar');
```

`tsc -p .` pasa con el esqueleto. `eslint .` no: marca los cuatro
parámetros como definidos y sin usar (`@typescript-eslint/no-unused-vars`).
Es lo esperado mientras no haya implementación; por eso el paso 3 pide solo
`tsc`, y `make check` completo se corre en el paso 6.

## 5. Para quien use una herramienta de IA (paso 4)

Denle **solo** la especificación y la firma: ni este archivo, ni el código
de Kallpa, ni sus pruebas. Guarden lo que le pidieron y lo que devolvió;
lo van a necesitar en `docs/registro-ia.md` (paso 8) y en la comparación del
paso 7. Antes de aceptar el código, léanlo contra su especificación: cada
decisión que tomó la herramienta donde la especificación calla es una
decisión que nadie revisó.
