# Reglas de equipo — correcciones y cambios en mbinv

> ⚠️ **Estas reglas SOLO las pueden reescribir Andrea o Manuel.** El resto —
> programadores y agentes de Claude— las **leen y las siguen**. Cualquier cambio a
> este archivo requiere la aprobación de Andrea o Manuel (ver `CODEOWNERS`).
>
> Este archivo es la **fuente única** de las reglas del equipo, compartida por todas
> las cuentas de Claude (grupo y personales) porque vive en el repo. No copiar las
> reglas a la memoria personal de nadie: se leen de acá.

---

## 1. LEY: nada sin tiquete

**Nunca** se trabaja una corrección, modificación o cambio **sin un tiquete**. Si ya
hay algo en curso sin tiquete, **crear uno** antes de seguir. Pasa muy seguido que
soporte reporta por chat, se arranca sin tiquete, se olvida y queda en el aire — sin
bitácora, sin dueño. El tiquete es lo que hace que el trabajo exista.

## 2. Nada se da por probado sin evidencia

- **Antes/después**, probado **en pruebas** (nunca en producción). `php -l` es solo
  sintaxis, **no** es prueba.
- Los **comentarios del bot (Copilot/codex)** los revisa y resuelve **quien hace el
  fix**, antes de pedir review humano — no dejarlos colgando.
- El tiquete lleva una **guía de prueba completa**: qué sitio/URL (el ambiente aislado
  de la rama), paso a paso qué hacer, qué se debe ver (antes vs después), **y qué hacer
  según el resultado** (ver sección 3).
- **Se prueba por el camino que usa la gente, no por el más cómodo.** Si el cambio se
  usa desde una pantalla, la prueba es **clic real en el botón real**, con sesión real.
  Un `curl` que devuelve 200 **no** prueba que el botón funcione: el navegador manda
  cabeceras, preflight de CORS y cookies que `curl` no manda. Lo mismo aplica a probar
  una consulta suelta en vez de la pantalla, o el endpoint en vez del flujo completo.
- **Si solo se pudo probar por el camino cómodo, hay que decirlo.** "Probado por API,
  falta probarlo desde la pantalla" es una entrega honesta; reportarlo como verificado
  a secas es lo que deja bugs vivos con el tiquete cerrado.

> **De dónde salió esta regla** (ago-2026): el panel de huellas rompió **dos veces** el
> mismo botón, y las dos veces la verificación previa estaba en verde. Primero, CORS sin
> `methods` explícito bloqueaba PUT/DELETE solo en el navegador. Después, el cliente HTTP
> mandaba `Content-Type: application/json` en peticiones sin cuerpo, y el servidor
> respondía **400 "Bad Request"** — con eso, los tres botones de Eliminar del panel nunca
> funcionaron desde el navegador. En los dos casos `curl` pasaba limpio, porque `curl` no
> manda esas cabeceras. No fue falta de pruebas: fue probar por donde no era.

## 3. Flujo de estados

`En Desarrollo` → `Pruebas de QA` → (el dueño **mergea**) → **`Resuelto`** → **vuelve a
Soporte** → Soporte actualiza al cliente **en el horario acordado** → **visto bueno del
cliente** → `Cerrado`.

- **Nunca `Cerrado` sin el OK del cliente.**
- Si en QA **no funciona**: no cerrarlo; documentar qué se vio y en qué paso (captura +
  status), estado a `En Desarrollo`, y reasignar al dueño con esa evidencia.

## 4. Marcar EN PROGRESO

Al crear un tiquete y empezar a trabajarlo de una, **indicarlo** (estado + asignación)
para que nadie duplique el esfuerzo.

## 5. Asignación y escalación

- **PT (POSTouch) → Andrea** (única que lo ve). **BO → el programador del módulo** (ver
  el mapa de dominios; se regenera del `git blame` reciente).
- **Escala a Manuel** si es **urgente** (cliente esperando) y no hay respuesta en un
  tiempo razonable. **Trivial** (detectado proactivamente, sin cliente detrás) → espera
  al **día hábil**.
- Programadores de BO y otros sistemas: **lunes a viernes, horario variable (HO)**. Para
  lo no-urgente, el "tiempo razonable" cuenta **solo horas hábiles**.
- **Guía (no ley):** no desplegar/actualizar **viernes ni fin de semana**, salvo
  corrección urgente — para no hacer trabajar a programación en horario inhábil.

## 6. Auto-corrección: cuándo el agente consulta

- **Confianza alta** (reproduce el error, señala la línea exacta, y el fix sigue un
  patrón que el propio código ya usa) → **arregla y presenta el PR**.
- **Confianza baja** → **consulta el diagnóstico al programador ANTES de escribir
  código** (validar el disparador).
- Si el agente **se estanca**, para y consulta con *"esto descarté (A, B, C), esto
  necesito (X)"* — no seguir cavando.

## 7. Dominio: las ventas se hacen solo desde el PT

Las ventas se crean **únicamente desde el PT (POSTouch)**, no desde el Back Office. Al
sugerir pruebas de documentos en el BO, **no usar una venta** de ejemplo — usar un
**traslado** o un **ajuste** (que sí se hacen en el BO y no llevan proveedor).

## 8. Ambiente de prueba aislado por rama

`probar-rama.sh <rama>` (en el repo `oci-dr`) monta un ambiente aislado en pruebas con
URL clicable `<slug>.pruebas.sistemasmb.com` (wildcard DNS ya creado). **Cada rama en
su caja** — dos cambios nunca se pisan. Para diagnosticar, `app_dev.php` muestra la
excepción y el status reales. Borrar con `probar-rama.sh <rama> --borrar`.

## 9. Fechas y horas: siempre Guatemala, anclada explícita

Todo lo que **compare, guarde o dispare por fecha/hora** (agendadores, cron, sellos de
tiempo, "vence el…", "actualizar a las…", reportes con hora) usa **hora de Guatemala
anclada de forma explícita** (UTC−6; Guatemala no tiene horario de verano) — **nunca** la
hora "local" del sistema operativo ni UTC crudo.

El "ahora" sin zona (`now()` / `datetime.now()` / `new Date()`) depende de cómo esté
configurado **ese** servidor. El default de casi todo servidor cloud es **UTC**, así que un
`now()` naive se corre **6 horas** y el reloj dispara a la hora equivocada **sin dar ningún
error** — nadie se entera hasta que un despliegue o un aviso sale a deshora.

- **Al revisar o escribir cualquier cambio que toque tiempo**, verificá de dónde sale el
  "ahora", en qué zona se guarda y en qué zona se compara. Si no está anclado a GT de forma
  explícita, es un **bug latente** aunque hoy funcione.
- En **reportes y mensajes al equipo**, mostrar la hora en **GT** (las fuentes —OCI,
  Freshdesk, logs— suelen devolver UTC; convertir antes de mostrar).
- **Ejemplo real (6-ago-2026, #23102):** el agendador del panel de despliegues comparaba
  con `datetime.now()` naive. Funcionaba solo porque el servidor estaba en
  `America/Guatemala`; pasarlo a UTC habría corrido cada despliegue programado 6 h. Se
  ancló con un offset fijo GT (`datetime.now(GT)`), correcto aunque el servidor esté en UTC.

---

## Mapa de dominios (quién toca qué)

Por actividad reciente (últimos 12 meses), excluyendo a Manuel (backstop):

- **Christian** — la mayor parte del BO activo: Maedoc, Maecli, Fisico, Producto, Dic,
  BackOrder, Procesos, Reparaciones, Tiquetes…
- **Saraí** — Traslado, TrasladoEnTransito, Documento, Consultas, Parametros…
- **Andrea** — PT (POSTouch) siempre + lo que tocó del BO.
- **Manuel** — backstop / módulos maestros dormidos sin autor reciente.

**Ex-empleados — no asignarles nada:** JC (JC04mb), jmorales17.

> El mapa es **vivo**: se regenera del `git blame` reciente porque la actividad se
> mueve. No tomarlo como fijo.
