# Línea de tiempo de acciones de agentes: compara las marcas de tiempo sin engaños

Una línea de tiempo de acciones de un agente puede contar una mentira convincente aunque todos los sistemas hayan registrado una marca de tiempo honesta. La mentira aparece cuando el investigador trata la hora que muestra un reloj local, la recepción en un servidor de API y un registro de auditoría como evidencias intercambiables de un mismo momento.

Guarda las marcas de tiempo tal como se observaron, con sus desplazamientos numéricos y su fuente. Después, compáralas como relojes separados, cada uno con su propio significado. Esto requiere algo más de información que un único campo `created_at`, pero evita el informe de incidente habitual en el que el agente parece haber actuado antes de recibir la aprobación o una solicitud de API parece terminar antes de empezar.

## Una sola marca de tiempo no puede describir una acción

Una acción tiene más de un momento relevante. Un agente puede decidir llamar a una API en un instante, enviar los datos un poco después, llegar al servidor más tarde y recibir un resultado después de que el servidor termine su trabajo. Cada evento puede ser importante cuando alguien pregunta si el agente excedió su autoridad.

Un registro típico contiene al menos estas afirmaciones:

- El proceso del agente indica cuándo empezó la acción.
- El servidor receptor indica cuándo aceptó la solicitud.
- El servidor receptor puede indicar cuándo confirmó o terminó el trabajo.
- La puerta de enlace de acciones indica cuándo recibió y liberó la solicitud.
- Una persona puede ver una hora local en una interfaz de usuario.

No son versiones enfrentadas de un mismo campo. Describen puntos distintos de una secuencia causal. Si los reduces a una única marca de tiempo normalizada al recopilarlos, pierdes la distinción que explica las colas, el retraso de red, los reintentos, las esperas de aprobación y las llamadas largas.

He visto equipos etiquetar una entrada de auditoría de API como la hora en que el agente «hizo la acción», cuando la entrada solo mostraba la aceptación de la solicitud. El error se vuelve costoso cuando el endpoint pone el trabajo en cola y realiza el cambio mucho después. El agente puede haberse detenido antes de que ocurriera el cambio, pero su solicitud aun así lo provocó.

Usa nombres que indiquen el evento. `agent_action_started_at`, `gateway_received_at`, `server_received_at` y `server_completed_at` obligan al lector a preguntarse qué ocurrió en cada punto. Un campo impreciso llamado `timestamp` anima a inventar una respuesta más adelante.

## Un desplazamiento conserva un instante y una zona explica la representación

Un desplazamiento UTC numérico convierte una lectura del reloj de pared en un instante concreto. Una zona horaria con nombre explica las reglas civiles que produjeron esa lectura. A menudo necesitas ambas, pero resuelven problemas distintos.

Considera estos dos valores:

```text
2025-11-02T01:30:00-04:00
2025-11-02T01:30:00-05:00
```

La esfera del reloj muestra la 1:30 en ambos casos. Sin embargo, están separados por una hora. En los cambios de vuelta del horario de verano de Norteamérica, la hora local se repite y un valor sin calificar como `2025-11-02 01:30:00` impide al investigador determinar qué instante ocurrió.

RFC 3339 aborda directamente este problema. Su formato de marca de tiempo usa una fecha y hora completas, junto con `Z` para UTC o un desplazamiento numérico. RFC 3339 también permite el desplazamiento `-00:00` para indicar que la fuente conoce la hora, pero no conoce el desplazamiento local. Esa diferencia es una evidencia útil. No conviertas silenciosamente `-00:00` en `Z`: UTC afirma un hecho que la fuente no afirmó.

Conservar un identificador de zona como `America/Los_Angeles` sigue siendo útil cuando una aprobación humana, un ticket de soporte o una grabación de pantalla hacen referencia a la hora local de una oficina. Permite al investigador reproducir las reglas del calendario vigentes en ese lugar. No sustituye al desplazamiento. Las reglas de las zonas pueden cambiar y una misma zona tiene distintos desplazamientos a lo largo del año.

Guarda la marca de tiempo recibida como cadena, conserva su desplazamiento original y deriva un instante UTC para ordenar. No conserves únicamente una cadena local ya representada. La representación debe producirse en el extremo de presentación, cuando una persona elige una zona horaria.

## Los relojes local, del servidor y de auditoría responden preguntas distintas

La hora local indica qué creía que era la hora el operador o el equipo donde se ejecutaba el agente. La hora del servidor indica cuándo un servicio remoto observó o realizó el trabajo. La hora de auditoría indica cuándo el sistema de registro aceptó un evento. Los investigadores deben comparar las tres, no elegir una como verdad universal.

Empieza por el límite del evento. Si un agente solicita `POST /deployments`, su hora local de acción puede respaldar una explicación de la intención. La hora de recepción del servidor puede establecer cuándo el servicio remoto se hizo responsable de la solicitud. La hora de finalización del servidor puede establecer cuándo cambió el estado de un despliegue. Una entrada de auditoría puede establecer cuándo tu punto de control observó el intento y si lo aprobó.

La latencia de red crea intervalos normales entre estos valores. Las colas crean intervalos mayores. Los reintentos complican las cosas porque un cliente puede usar un único identificador de acción para varios intentos, mientras el servidor registra cada intento por separado. Una línea de tiempo que solo muestra la primera hora local oculta todo eso.

No uses la hora que muestra un navegador, un indicador de terminal o una captura de pantalla como desempate, salvo que sepas cómo sincronizaba la hora ese dispositivo. Esas representaciones suelen ayudar a explicar lo que creía una persona, pero rara vez resuelven una disputa de orden muy ajustada.

Una comparación práctica usa tres columnas en la hoja de trabajo de la investigación:

| Fuente de evidencia | Qué conservar | Qué permite responder |
|---|---|---|
| Equipo del agente | Marca de tiempo local sin procesar, desplazamiento, zona e identidad del proceso | ¿Cuándo afirmó este proceso que comenzó o recibió un resultado? |
| Servicio remoto | ID de solicitud, hora de recepción, hora de finalización y estado de respuesta | ¿Cuándo aceptó y realizó el trabajo el servicio? |
| Sistema de auditoría | ID del evento, hora registrada, prueba de integridad y resultado de autorización | ¿Cuándo observó y permitió o denegó la llamada el punto de control? |

Las filas deben conservar sus propias horas incluso después de añadir una columna UTC calculada para ordenar. Una hoja de cálculo limpia con una sola columna de tiempo parece cómoda, pero oculta la cadena de evidencia.

## Los cambios de horario de verano crean horas duplicadas y horas inexistentes

Las transiciones del horario de verano exponen los atajos relacionados con las marcas de tiempo porque rompen una suposición humana: que cada minuto local ocurre una sola vez y que todos los días tienen la misma duración. Ninguna de las dos cosas es cierta.

Durante el cambio de otoño, una hora local se repite. Durante el cambio de primavera, una hora no existe. Un analizador que acepta una marca de tiempo local sin calificar debe elegir una regla, rechazar la entrada o adivinar. Adivinar es inaceptable en una ruta de auditoría.

El siguiente registro es utilizable porque contiene tanto un instante preciso como el contexto civil que lo generó:

```json
{
  "event_id": "act_8f3c",
  "event": "authorization_granted",
  "observed_at": "2025-11-02T01:14:22-04:00",
  "zone": "America/New_York",
  "instant_utc": "2025-11-02T05:14:22Z",
  "clock_source": "agent_host"
}
```

El campo `instant_utc` se deriva, por lo que también debes conservar la cadena original `observed_at`. Si más adelante cambia el analizador o un error afecta a la conversión, podrás volver a calcularla y explicar la diferencia. Trata los valores derivados como resultados del análisis, no como sustitutos de la evidencia original.

Una abreviatura de zona como `EST` empeora las cosas. Las abreviaturas son ambiguas entre regiones y no indican de forma fiable si estaba vigente el horario de verano. Usa un identificador de zona IANA para el contexto civil y un desplazamiento numérico para el instante. Si una fuente solo emite una abreviatura, regístrala exactamente y deja constancia de que su significado sigue sin resolverse.

Las programaciones recurrentes necesitan su propia regla. Guarda la programación como una hora local junto con una zona IANA y calcula cada aparición según las reglas de esa zona. Guarda una acción que realmente se ejecutó como una marca de tiempo con desplazamiento. Una programación indica cuándo debía ejecutarse un trabajo; un registro de evento indica cuándo se ejecutó.

## La deriva del reloj convierte un orden aparentemente preciso en una falsa certeza

La precisión en milisegundos no significa exactitud en milisegundos. Un portátil sin sincronizar puede producir marcas de tiempo con seis decimales y estar varios minutos desfasado respecto a un servidor. La suspensión, la pérdida de red, las máquinas virtuales y una sincronización defectuosa producen este problema.

Separa la precisión de la incertidumbre en tu modelo de datos. La precisión es el número de dígitos registrados. La incertidumbre es el intervalo en el que crees que cae el instante real. Una marca de tiempo del equipo como `10:00:00.123Z`, con una incertidumbre de dos segundos, no debe resolver una disputa de orden de un segundo con una API remota.

Mide el desfase del reloj cuando puedas. Captura la hora de una referencia fiable antes de ejecutar el agente y otra vez después, y guarda la diferencia observada. Si la referencia es remota, ten en cuenta el tiempo de tránsito de la solicitud. Una estimación sencilla basada en el punto medio funciona para operaciones aproximadas cuando conservas la medición en lugar de presentarla como una corrección exacta.

Por ejemplo, un recopilador envía una solicitud a las `10:00:00.000` en la hora local, recibe una respuesta fiable a las `10:00:00.200` en la hora local y la respuesta indica `10:00:00.150Z`. La hora del servidor ocurrió en algún momento del viaje de ida y vuelta. El punto medio local es `10:00:00.100`, por lo que el equipo parece estar unos 50 milisegundos atrasado bajo la suposición habitual de un tránsito simétrico. Esa suposición puede fallar, por eso el resultado útil es un intervalo y no una declaración de verdad.

Los relojes monotónicos resuelven un problema más limitado. Un reloj monotónico mide el tiempo transcurrido dentro de un proceso en ejecución y no salta cuando cambia la hora de pared. Registra un valor monotónico inicial y la duración junto con la hora de pared cuando necesites demostrar que la acción B siguió a la acción A dentro del mismo proceso. No conviertas valores monotónicos a UTC ni los compares entre equipos.

La documentación de NTP establece una distinción práctica parecida: la sincronización estima el desfase y la dispersión, pero no concede una hora perfecta. Trata esas estimaciones como parte de la evidencia cuando el orden sea lo bastante ajustado como para importar.

## Conserva la evidencia original y la hora normalizada en el mismo registro

Un esquema de eventos defendible conserva lo que informó realmente cada participante y hace reproducible el análisis. La siguiente estructura JSON funciona para una acción de agente sin fingir que todos los campos proceden de un mismo reloj.

```json
{
  "action_id": "a91c2d7e",
  "attempt": 2,
  "agent": {
    "process_id": "p_4b71",
    "started_at": "2025-04-18T14:07:12.481-07:00",
    "zone": "America/Los_Angeles",
    "monotonic_start_ms": 9184421,
    "clock_uncertainty_ms": 750
  },
  "gateway": {
    "received_at": "2025-04-18T21:07:12.661Z",
    "authorized_at": "2025-04-18T21:07:14.034Z",
    "result_released_at": "2025-04-18T21:07:14.882Z",
    "audit_event_id": "aud_3e90"
  },
  "server": {
    "request_id": "req_7c19",
    "received_at": "2025-04-18T21:07:14.301Z",
    "completed_at": "2025-04-18T21:07:14.649Z",
    "status": 201
  },
  "normalization": {
    "sort_instant_utc": "2025-04-18T21:07:12.481Z",
    "method": "RFC3339 offset conversion"
  }
}
```

Este esquema marca un límite que los equipos suelen difuminar: un identificador de acción conecta los registros, mientras que una marca de tiempo ordena un evento dentro de esa acción. Reutilizar un identificador después de un reintento tiene sentido. Reutilizar una única marca de tiempo para todas las etapas, no.

Registra el ID de solicitud del servidor aunque ya tengas un ID de acción interno. Durante una investigación, el identificador propio del servidor suele ser la única forma fiable de distinguir una solicitud que agotó el tiempo de espera de otra que nunca salió del cliente.

Evita guardar únicamente milisegundos desde la época, salvo que el productor garantice UTC y documente la fuente de su reloj. Los valores de época se ordenan fácilmente, pero pierden el desplazamiento original, el contexto de presentación y, a veces, la unidad. Si los aceptas de terceros, registra explícitamente la unidad y conserva la representación recibida.

## Una línea de tiempo necesita intervalos cuando las evidencias se solapan

Cuando dos fuentes tienen incertidumbre, calcula intervalos en lugar de forzar un orden. Así evitas un error habitual: un investigador ve `10:03:01.010` y `10:03:01.400`, los ordena y afirma que el primer evento causó el segundo, aunque los desfases de los dos equipos sean desconocidos.

Supón que el agente informa del inicio de una acción a las `21:07:12.481Z` con 750 milisegundos de incertidumbre. Su intervalo posible va de `21:07:11.731Z` a `21:07:13.231Z`. La puerta de enlace informa de la recepción a las `21:07:12.661Z`, con una incertidumbre de 20 milisegundos. Los intervalos se solapan, así que las marcas de tiempo por sí solas no pueden demostrar que la puerta de enlace recibió la llamada después del inicio declarado. La secuencia del protocolo aún puede respaldar esa conclusión, pero los relojes de pared no.

Explica el motivo de cada afirmación sobre el orden. Estas conclusiones son distintas:

- «La puerta de enlace registró la recepción después de que el agente emitiera la solicitud» se deduce de la evidencia del protocolo o de un rastro de solicitud correlacionado.
- «La marca de recepción de la puerta de enlace es posterior» se deduce únicamente de las horas de pared mostradas.
- «Los registros establecen el orden dentro de su incertidumbre declarada» se deduce cuando los intervalos no se solapan.
- «Los registros no pueden establecer el orden» es el resultado correcto cuando los intervalos se solapan y ninguna evidencia causal cubre la diferencia.

A la gente no le gusta la cuarta conclusión porque los informes de incidentes quieren una historia ordenada. Inventar precisión no mejora la historia. Da al siguiente revisor un motivo para desconfiar de todas las conclusiones que la rodean.

Esto también cambia el diseño de las alertas. No señales a un agente solo porque un evento de la puerta de enlace parezca ocurrir unos cientos de milisegundos antes del inicio local del agente. Señala un tiempo transcurrido negativo únicamente después de aplicar los límites de desfase conocidos, o márcalo para investigar el estado del reloj.

## La aprobación y la ejecución deben conservar marcas de tiempo separadas

Una aprobación humana demuestra que alguien permitió una capacidad en un momento concreto. No demuestra que el agente enviara una solicitud en ese mismo instante y, desde luego, no demuestra que un sistema remoto terminara entonces el trabajo solicitado.

Mantén los eventos de aprobación separados de las llamadas. Un registro de aprobación debe incluir al actor, el alcance concedido, el proceso o sesión a la que se aplicaba, la hora observada y el ID del evento del sistema de autorización. Un registro de llamada debe hacer referencia a esa autorización cuando corresponda y conservar sus propias horas de recepción y liberación.

Esta distinción importa especialmente con la autorización de sesiones. Una aprobación puede cubrir varias acciones durante la vida de un proceso. Si una acción posterior causa daños, el investigador debe responder a dos preguntas distintas: ¿cuándo se produjo la autorización y el proceso seguía dentro de la sesión aprobada cuando realizó esta llamada? Un único campo `approved_at` no puede responder a ambas.

La aprobación por llamada crea una secuencia más estrecha, pero aún deja un intervalo. El usuario puede aprobar a las 14:07:14, la puerta de enlace puede despachar la llamada a las 14:07:14.1 y el servicio remoto puede confirmar el cambio a las 14:08:02. Un tiempo de espera remoto después del despacho no elimina la posibilidad de que el servicio completara la acción.

En un flujo controlado por una puerta de enlace, registra también los eventos de denegación. Una llamada denegada demuestra que el agente intentó una acción, aunque no debiera haberse producido ninguna solicitud remota. Si el agente vuelve a intentarlo después de un cambio de permisos, la línea de tiempo necesita intentos separados con evidencias separadas. No sobrescribas una denegación con un éxito posterior.

## Analiza un despliegue discutido sin aplanar la evidencia

Supón que un agente solicitó un despliegue después de que un desarrollador aprobara una sesión. Más tarde, el desarrollador afirma que la aprobación ocurrió fuera del horario laboral, mientras que el registro del servicio remoto indica que el despliegue comenzó antes de la aprobación. La contradicción aparente suele surgir al comparar la hora local mostrada con la hora UTC del servidor.

La evidencia contiene estos registros:

| Evento | Hora indicada | Fuente |
|---|---|---|
| Aprobación de la sesión | `2025-04-18T17:58:40-07:00` | Registro de autorización local |
| El agente inicia la llamada de despliegue | `2025-04-18T17:59:02-07:00` | Equipo del agente |
| La puerta de enlace recibe la llamada | `2025-04-19T00:59:02.410Z` | Registro de auditoría de la puerta de enlace |
| El servicio remoto acepta la solicitud | `2025-04-19T00:59:04Z` | Registro de auditoría del servicio |
| El servicio remoto termina el despliegue | `2025-04-19T01:01:18Z` | Registro de auditoría del servicio |

Convierte los dos primeros registros, pero conserva sus formas originales. La aprobación ocurrió a las `00:58:40Z` y el agente comenzó a las `00:59:02Z`. Los registros de la puerta de enlace y del servicio siguen una secuencia causal plausible. Nada ocurrió antes de la aprobación; alguien simplemente leyó `17:58` junto a `00:59` como si ambos valores usaran la misma representación de reloj.

Ahora añade la parte incómoda. Supón que el equipo del agente tiene una incertidumbre estimada de 90 segundos porque había estado en suspensión. Aún puedes afirmar que la puerta de enlace recibió una llamada después de que el sistema de autorización registrara la aprobación, porque esos registros usan la pista de la puerta de enlace y la autorización. No puedes usar la hora local de inicio del agente para establecer un orden más preciso dentro de ese intervalo.

La investigación debe conservar ambas conclusiones. Una es sólida y la otra tiene límites. Es mejor que hacer que toda la línea de tiempo parezca igual de precisa.

## Verifica la integridad de la auditoría antes de confiar en su posición temporal

Un registro de auditoría solo puede decirte si alguien alteró, reordenó o eliminó evidencias cuando verificas su mecanismo de integridad. Haz esa verificación antes de usar las entradas de auditoría para respaldar una secuencia. Después, plantea la pregunta independiente de qué reloj puso la marca de tiempo en cada entrada.

Sallyport proyecta los diarios de sesiones y llamadas desde un único registro de auditoría cifrado y encadenado mediante hashes, y `sp audit verify` puede verificar esa cadena sin conexión sobre texto cifrado. Esta comprobación permite al investigador probar la continuidad del registro sin exponer los secretos almacenados.

La integridad no convierte una marca de tiempo de auditoría en un reloj global perfecto. Una entrada válida demuestra que el registro contiene el evento registrado dentro de su cadena. Si quieres compararla con precisión con un servidor externo, todavía necesitas una fuente de reloj documentada, un formato de desplazamiento y una política de incertidumbre.

Ejecuta la verificación sobre la copia de evidencia y guarda el resultado del comando junto con el material del caso. Un registro útil incluye el comando, el identificador del artefacto de entrada, el resultado de la verificación y la persona o tarea automatizada que la realizó. No pegues únicamente una línea verde de estado en un ticket. El siguiente investigador necesita poder repetir la misma comprobación.

El encadenamiento mediante hashes también cambia la forma de tratar los huecos. Si la cadena indica que faltan entradas o que han sido alteradas, no continúes discretamente con una línea de tiempo normalizada. Marca el intervalo afectado como incompleto y busca registros independientes del servidor. Un segmento de auditoría ausente puede decir más sobre el incidente que las entradas que lo rodean.

## Construye la vista de investigación a partir de suposiciones declaradas

Una buena vista de investigación muestra las marcas de tiempo originales, las conversiones a UTC, la identidad de la fuente y la incertidumbre. No oculta la conversión detrás de una etiqueta de panel como «hora del evento». El lector debe poder ver por qué la representación ordena dos eventos.

Usa esta secuencia al montar una línea de tiempo de acciones:

1. Recopila los registros de origen inmutables y conserva sus cadenas de marca de tiempo originales, identificadores y desplazamientos.
2. Identifica el evento que marca cada hora: decisión, aprobación, recepción en la puerta de enlace, aceptación del servidor, finalización o liberación del resultado.
3. Convierte las marcas de tiempo con desplazamiento a UTC en un campo separado y registra el analizador o método utilizado.
4. Estima la incertidumbre del reloj de cada fuente que pueda afectar al orden discutido.
5. Ordena por instantes normalizados y después revisa los intervalos de incertidumbre solapados y los ID de solicitud antes de escribir afirmaciones causales.

No conviertas una marca de tiempo local añadiendo el desplazamiento actual del investigador. Ese error cambia la posición de los eventos históricos cuando el investigador trabaja en otra zona o cuando las reglas del horario de verano son diferentes. Analiza el desplazamiento que acompaña al registro. Si el registro no tiene desplazamiento, márcalo como no resuelto hasta que puedas establecer una zona de origen y sus reglas aplicables.

Los equipos deberían probar esto antes de un incidente. Crea una acción cerca de un cambio de horario de verano en un entorno que no sea de producción. Cambia el reloj de un cliente dentro de un límite de prueba seguro. Fuerza un reintento y una respuesta retrasada del servidor. Después pide a alguien que no haya creado el sistema de registro que reconstruya el orden. Si necesita contexto verbal para explicar la evidencia, el formato del registro está incompleto.

La hora rara vez es la única evidencia en un incidente de un agente. Los identificadores de solicitud, el alcance de la autorización, la identidad del proceso, los cuerpos de respuesta y las comprobaciones de manipulación suelen establecer hechos que los relojes no pueden demostrar. Mantén esos hechos unidos a sus propios eventos. La próxima acción discutida será más fácil de explicar porque registraste lo que sabía cada sistema, en lugar de obligarlos a coincidir en una única marca de tiempo ficticia.
