Capa de interoperabilidad · Prueba técnica de arquitectura

ADR-018: marca de sincronización de cada fuente para calcular `asOf` y `stale`

Aceptado el 10/11/2026 por Andrés.

Contexto

docs/to-be/05-modelo-de-lectura.md dice que toda respuesta de stock y precio lleva asOf y que, si el dato supera el umbral (stock 5 minutos, precio 30 minutos), sale stale: true. El verificador F10 de F3 lo exige: con el ERP caído, primero 200 y luego stale: true.

El diseño no dice qué es asOf para un dato que no cambia. Si es el momento del último cambio de la llave, un precio estable desde hace tres días sale siempre stale: true aunque el ERP esté sano, y el indicador deja de servir. Si es el momento en que el servicio leyó el evento, el problema es el mismo. Lo que el canal necesita saber es otra cosa: hasta qué momento la capa sabe que ese dato sigue siendo el del sistema de origen.

Esa información la tiene solo el adaptador: sabe hasta qué posición leyó el feed del ERP o del WMS y cuándo lo consultó con éxito por última vez. Hoy no la publica.

Opciones

Opción A favor En contra
A. Cada adaptador publica una marca de sincronización por fuente en un tópico compactado Un evento pequeño cada pocos segundos; asOf y stale quedan bien definidos; la caída del legado se nota sin que nadie consulte al adaptador Un canal y un mensaje nuevos en el contrato; dos servicios más lo consumen
B. asOf igual al último cambio de la llave Sin trabajo Datos estables marcados como desactualizados; F10 no distingue un ERP caído de un precio que no cambió
C. pricing e inventory consultan la salud del adaptador por HTTP Sin contrato de eventos nuevo Llamada síncrona interna que la regla 2 no permite; acopla la lectura al adaptador
D. El adaptador republica todas las llaves cada cierto tiempo Sin mensaje nuevo 50.000 SKU por canales y ubicaciones (supuesto 4): carga sobre Kafka y sobre el legado sin valor

Decisión

Opción A.

  1. Canal nuevo andes.sources.sync.v1, compactado, clave system (erp, wms). Mensaje SourceSynced con system, position (lsn del ERP o seq del WMS) y syncedAt (UTC).
  2. El adaptador lo publica tras cada sondeo exitoso, y solo después de que Kafka confirmó los eventos de los cambios hasta esa posición. Como máximo uno cada 15 segundos (supuesto: 20 marcas dentro del umbral de stock de 5 minutos; no cambia la frescura de los cambios, que viajan por su propio evento). Si el legado no responde o el circuito está abierto, no publica.
  3. pricing-service consume la marca del ERP; inventory-service, la del WMS. asOf de una llave es el más reciente entre el momento del dato y el syncedAt de su fuente. stale es now - asOf mayor que el umbral.
  4. Con el ERP caído, la marca deja de avanzar y, pasado el umbral, todas las respuestas de precio salen con stale: true. Eso es F10.

Verificación

Qué se sacrifica