# Ordonner les activités d'un agent pour reconstituer les incidents de manière fiable

L'ordre des activités d'un agent détermine si un rapport d'incident explique ce qui s'est passé ou se contente d'afficher une pile d'horodatages. Lorsqu'un agent de programmation autonome peut appeler des API et ouvrir des sessions SSH, les enquêteurs doivent établir quel processus a agi, ce qu'il a tenté, ce qui s'est terminé et quel résultat l'agent a reçu avant de choisir son action suivante.

Une liste triée par heure ne suffit pas. Les horloges dérivent, les requêtes se chevauchent, les réponses arrivent dans le désordre et un délai d'attente peut masquer une action qui a pourtant réussi à distance. Construisez des enregistrements qui préservent le contexte de session, un ordre local durable et des horodatages distincts pour chaque étape du cycle de vie. Sinon, le premier incident sérieux transformera votre piste d'audit en débat fondé sur des suppositions.

## Le temps seul ne suffit pas à établir l'ordre des actions

Un horodatage indique quand une horloge a observé un événement. Il ne prouve pas que cet événement s'est produit avant tous les autres événements portant un horodatage ultérieur. Cette distinction peut sembler théorique, jusqu'à ce que deux appels quittent rapidement un agent, qu'un service distant ralentisse et que le second appel revienne en premier. Trier par `completed_at` donne l'ordre des réponses, pas l'ordre des décisions de l'agent.

Chaque appel comporte plusieurs moments importants. L'agent décide d'invoquer un outil. La passerelle accepte la requête. Elle l'autorise. Elle transmet le travail à un service HTTP ou à un utilitaire SSH. Le système distant peut l'accepter. Une réponse revient. La passerelle transmet ce résultat à l'agent. Traiter tout cela comme un seul événement supprime les éléments nécessaires pour expliquer une défaillance.

Conservez un `call_sequence` local et monotone pour chaque session. Attribuez-le lorsque la passerelle accepte un appel, avant tout échange réseau. Ce nombre répond à une question utile et limitée : « Dans quel ordre cette passerelle a-t-elle accepté les appels de ce processus d'agent ? » Il ne prétend pas décrire l'ordre d'exécution distant. Une portée honnête vaut mieux qu'une affirmation générale impossible à défendre.

Utilisez une deuxième séquence durable pour le journal d'audit lui-même. Des appels provenant de sessions différentes peuvent se chevaucher, et les événements d'autorisation, de révocation, de verrouillage du coffre et de vérification doivent appartenir au même flux de preuves. La séquence du journal indique à l'enquêteur l'ordre d'écriture de l'enregistreur. La séquence d'appel de la session indique l'ordre des intentions au sein d'une exécution d'agent. Aucun de ces champs ne remplace l'autre.

N'utilisez pas la précision des horodatages à la place des numéros de séquence. Ajouter des décimales ne fait qu'enregistrer une lecture plus précise d'une horloge. Cela ne résout ni une correction d'horloge ni l'établissement d'un ordre total entre des écrivains concurrents.

RFC 3339 définit une représentation interopérable utile pour les horodatages basés sur l'heure civile, avec notamment un décalage UTC explicite. Utilisez sa forme UTC, par exemple `2025-03-08T21:14:03.482Z`, pour les exports et les vérifications humaines. RFC 3339 ne promet pas l'ordre causal. C'est le rôle de votre enregistreur, qui a besoin de champs de séquence et de limites d'événements clairement définies.

## Une session identifie le processus qui agit, pas une tâche vague

Une session doit rattacher une exécution ordonnée au processus d'agent précis qui a reçu l'autorisation d'agir. Elle doit commencer lorsque ce processus établit une connexion et se terminer lorsqu'il se ferme, perd son canal ou qu'un opérateur révoque son autorisation. Ne faites pas d'une session le synonyme de « travail sur le ticket 184 » ou de « déploiement de l'après-midi ». Ces libellés peuvent faciliter les recherches, mais ils ne définissent pas une limite d'exécution.

L'enregistrement de session doit contenir suffisamment d'informations pour répondre aux questions que les enquêteurs se posent réellement : quel exécutable s'est connecté, qui l'a signé, quel utilisateur local l'a lancé, quel transport l'a connecté et quand son autorisation a commencé et pris fin. Enregistrez des identifiants attestés par le système d'exploitation ou la connexion. Ne laissez pas l'agent inscrire ses propres déclarations d'identité dans les champs faisant autorité.

Cette séparation compte lorsqu'une personne copie une configuration d'outil dans un autre processus. La requête d'action peut déclarer son intention d'agir sur un dépôt précis. La passerelle doit enregistrer l'identité du processus qu'elle a observée. Lors d'un incident, cette seconde information a davantage de poids.

Un enregistrement de session pratique peut contenir :

```json
{
  "event_id": "01JNRQ2Q9Y9J0R3E5P8F7K2X4M",
  "journal_sequence": 8124,
  "event_type": "session.opened",
  "occurred_at": "2025-03-08T21:14:02.901Z",
  "session_id": "sess_7f31c4",
  "process": {
    "pid": 48102,
    "code_signing_authority": "observed signing authority",
    "local_user": "developer account"
  }
}
```

L'agent doit recevoir un identifiant de session opaque, sans pouvoir choisir l'identifiant de session ni modifier ses métadonnées. Il peut tout de même associer son propre libellé d'exécution, le chemin du dépôt ou la référence de la tâche dans un champ de contexte déclaré distinct. Marquez ces valeurs comme fournies par l'agent. Le libellé peut expliquer l'intention, mais il ne doit jamais remplacer les faits observés sur le processus.

L'autorisation par session offre un deuxième avantage pour les enquêtes. Elle enregistre une décision humaine liée à une exécution de processus limitée. Si cette exécution effectue ensuite un appel dommageable, les examinateurs peuvent voir l'événement d'autorisation qui l'a précédé ainsi que l'événement de fermeture ou de révocation qui y a mis fin. Une approbation qui s'applique silencieusement à des processus ultérieurs crée une lacune qu'aucun volume de journaux d'appels ne peut réparer.

## Un appel a besoin d'un cycle de vie, pas d'une seule ligne de fin

Un enregistrement d'appel utile préserve le cycle de vie d'une tentative. Il ne réduit pas une requête tentée, un envoi réseau, un résultat distant et le résultat visible par l'agent à un champ vague indiquant « succès » ou « échec ».

Commencez par un `call_id` immuable et la prochaine `call_sequence` de la session. Enregistrez un événement d'acceptation avant de contacter l'extérieur. Si une règle ou une approbation bloque la requête, l'événement d'acceptation et celui du refus restent importants. Ils montrent l'intention et le comportement du contrôle sans prétendre que l'action externe a eu lieu.

Pour une action HTTP autorisée, capturez les limites d'événements distinctes suivantes :

1. `call.accepted` enregistre la requête ordonnée au niveau de la passerelle.
2. `call.authorized` ou `call.denied` enregistre la décision de contrôle.
3. `call.dispatched` indique que la passerelle a remis la requête à son client réseau.
4. `call.result_received` enregistre le résultat du transport ou la réponse distante.
5. `call.result_returned` enregistre le résultat renvoyé à l'agent.

Les noms peuvent varier, mais pas la sémantique. Un résultat reçu n'est pas toujours un résultat renvoyé. La passerelle peut masquer une réponse, rejeter des données mal formées, perdre la connexion avec l'agent ou rencontrer une erreur interne en préparant le résultat. Les enquêteurs doivent pouvoir voir cette rupture.

Conservez `request_started_at`, `dispatched_at`, `result_received_at` et `result_returned_at` lorsque ces moments se produisent. Utilisez null pour un moment qui n'a pas eu lieu. N'inventez pas d'heure de fin lorsqu'un processus s'est arrêté brutalement. Enregistrez plutôt un événement de récupération ultérieur indiquant que l'enregistreur a trouvé un appel inachevé.

Cet exemple montre la structure d'une requête terminée sans exposer de jeton porteur ni le corps complet de la réponse :

```json
{
  "event_id": "01JNRQ3M8W7P0Q4R6S9T1V2X3Y",
  "journal_sequence": 8131,
  "event_type": "call.result_received",
  "occurred_at": "2025-03-08T21:14:05.841Z",
  "session_id": "sess_7f31c4",
  "call_id": "call_00017",
  "call_sequence": 17,
  "channel": "http",
  "target": "api.internal.example/v1/releases",
  "method": "POST",
  "dispatch_event_id": "01JNRQ3G2A...",
  "outcome": {
    "transport": "response",
    "http_status": 201,
    "response_digest": "sha256:..."
  }
}
```

Les condensés de la requête et de la réponse permettent de comparer les preuves conservées sans placer de secrets ou de grandes charges utiles sensibles entre les mains de tous les lecteurs du journal. Un condensé ne rend pas un secret sûr à journaliser. Les valeurs à faible entropie, les identifiants prévisibles et les jetons courts restent devinables. Excluez les identifiants au moment de la capture, puis décidez quels fragments de charge utile sont réellement nécessaires au processus d'incident.

## Les nouvelles tentatives et les délais d'attente créent l'ambiguïté la plus difficile

Un délai d'attente signifie que vous ne savez pas si le système distant a agi. Il ne signifie pas qu'il n'a rien fait. Les équipes se trompent souvent parce que les journaux applicatifs traitent l'expiration comme une simple erreur et la nouvelle tentative comme un remplacement de la première.

Imaginez un agent qui crée une version au moyen d'une requête HTTP. L'appel 41 reçoit un délai d'attente après son envoi. L'agent lit cet échec et envoie l'appel 42, une nouvelle tentative. Plus tard, le service distant traite les deux requêtes. Si votre journal a remplacé l'appel 41 par un état final « nouvelle tentative », les enquêteurs verront une requête réussie et manqueront l'action en double.

Donnez à chaque tentative réseau son propre `call_id` et sa propre `call_sequence`. Ajoutez `retry_of` lorsqu'une tentative suit directement une tentative antérieure. Préservez la cause visible par l'agent, par exemple une expiration, une réinitialisation de connexion ou un état reçu pouvant être retenté. Cette relation permet de suivre la chaîne sans l'aplatir.

Une séquence complète peut ressembler à ceci :

```text
sequence 41  accepted       21:14:11.024Z  create release, request r_8d2
sequence 41  dispatched     21:14:11.027Z
sequence 41  result_received 21:14:41.031Z timeout
sequence 41  result_returned 21:14:41.034Z timeout returned to agent
sequence 42  accepted       21:14:42.112Z  retry_of call_00041, request r_8d2
sequence 42  dispatched     21:14:42.115Z
sequence 42  result_received 21:14:42.490Z HTTP 201
sequence 42  result_returned 21:14:42.493Z HTTP 201 returned to agent
```

La référence répétée à la requête n'est utile que si l'API distante prend en charge un mécanisme d'idempotence ou un autre identifiant d'opération stable. Si le service accepte une clé d'idempotence, générez et enregistrez une clé non secrète qui reste constante entre les nouvelles tentatives d'une même opération prévue. Dans le cas contraire, indiquez que le risque lié à la nouvelle tentative n'est pas résolu. Ne prétendez pas qu'une opération est idempotente simplement parce que les charges utiles se ressemblent.

SSH pose un autre problème. Une commande peut s'exécuter à distance alors que la connexion échoue avant que le client ne reçoive la sortie ou le code de retour. Enregistrez l'envoi de la commande, l'identité de la connexion, la référence de l'hôte et l'état de terminaison observé. Étiquetez une commande SSH interrompue comme « résultat inconnu », et non comme « échec ». Une commande ultérieure qui vérifie l'état distant peut réduire l'incertitude, mais elle ne réécrit pas le résultat original.

Ne transformez pas tous les échecs en événements terminaux. Un refus d'autorisation est terminal pour cet appel, car aucun envoi externe n'a eu lieu. Une erreur DNS locale peut être terminale pour la tentative. Une expiration après le départ des octets de la machine laisse le résultat externe inconnu. Ces catégories entraînent des décisions différentes pendant un incident.

## Enregistrez deux types de temps et expliquez leurs limites

L'heure civile rend une chronologie lisible entre les systèmes. Le temps monotone mesure la durée écoulée sans être affecté par la synchronisation réseau ou une correction manuelle de l'horloge. Collectez les deux lorsque le système d'exploitation les fournit et précisez la signification de chacun dans votre schéma.

Pour chaque événement du journal, enregistrez une valeur UTC `occurred_at` au format RFC 3339. Pour les événements d'une session active, enregistrez également `monotonic_ns`, mesuré depuis l'origine de l'horloge monotone choisie par le processus. Ne comparez pas les valeurs monotones de machines différentes sans avoir établi explicitement une référence commune. Ce sont des mesures locales.

Une correction d'horloge peut produire des enregistrements déroutants comme celui-ci :

```text
journal 901  wall 21:19:07.900Z  monotonic 5562019921  call accepted
journal 902  wall 21:18:58.104Z  monotonic 5562026310  call dispatched
```

L'horloge civile a reculé. La séquence du journal et la valeur monotone montrent toujours que l'envoi a suivi l'acceptation. L'export doit conserver les horodatages originaux au lieu de les trier et de les réécrire silencieusement. Ajoutez un événement de l'enregistreur lorsque le système d'exploitation signale une modification importante de l'heure, si vous pouvez l'observer. Cet événement donne aux examinateurs une raison à l'écart.

La publication spéciale 800-92 du NIST, Guide to Computer Security Log Management, conseille aux organisations de synchroniser les horloges et de définir les exigences relatives aux données de journal avant un incident. Cette recommandation est juste, mais des horloges synchronisées ne suffisent pas à établir l'ordre au sein d'une exécution d'agent. La synchronisation améliore la corrélation avec une API distante, un service CI ou les journaux d'un hôte. Votre séquence locale établit toujours l'ordre de l'enregistreur.

Les horodatages distants méritent leurs propres champs. Un en-tête HTTP `Date`, un identifiant de requête fourni par un prestataire et une heure d'événement générée par le serveur sont des déclarations externes. Préservez leur source et leur valeur exacte. Ne les copiez pas dans `occurred_at` et ne les utilisez pas pour renuméroter votre journal local. Un horodatage distant peut aider à rapprocher les systèmes par la suite, mais il peut refléter une file d'attente, une autre horloge ou l'heure de génération de la réponse.

Les champs de durée ont eux aussi besoin d'une définition précise. `gateway_duration_ms` peut désigner le temps entre l'acceptation et le retour du résultat. `network_duration_ms` peut désigner le temps entre l'envoi et la réception du résultat. Écrivez la définition à côté du schéma. Sinon, un rapport indiquant qu'un appel a duré 30 secondes ne permettra pas de savoir si le retard s'est produit avant l'envoi, au niveau du service distant ou après le retour de la réponse.

## L'enregistreur d'audit doit choisir l'ordre avant de publier les résultats

Vous ne pouvez pas reconstituer l'ordre si des travailleurs concurrents écrivent les enregistrements dès qu'ils terminent. Donnez à l'enregistreur d'audit un chemin d'ajout unique qui attribue une séquence de journal, capture l'heure de l'événement, relie l'enregistrement précédent et valide l'enregistrement avant que le système n'indique à l'agent qu'un changement d'état ayant une portée externe s'est produit.

Cela n'exige pas un verrou géant autour de toute l'activité réseau. Les appels peuvent s'exécuter en parallèle. L'enregistreur n'a besoin que d'un point de validation sérialisé et étroit. Lorsqu'un travailleur atteint une limite d'événement, il transmet un événement à cet écrivain. L'écrivain attribue la prochaine séquence durable du journal. L'ordre obtenu reflète l'ordre de validation, ce que vous devez nommer avec précision dans la documentation et les exports.

Le schéma d'échec est courant. Le travailleur A accepte l'appel 17 et démarre une requête lente. Le travailleur B accepte l'appel 18 et termine rapidement. Si les travailleurs ajoutent uniquement leurs enregistrements de fin, le journal commence par le succès de l'appel 18. L'enquêteur ne peut pas savoir si l'appel 17 était en cours, n'a jamais été envoyé ou a été omis. Les événements d'acceptation et d'envoi de l'appel 17 comblent cette lacune.

Le chaînage par hachage ajoute une preuve d'intégrité à la séquence validée. Chaque entrée contient le condensé de l'entrée validée précédente et le condensé de son propre contenu canonique. La canonicalisation est importante. Les mêmes données doivent produire les mêmes octets avant le hachage. Spécifiez l'ordre des champs, l'encodage UTF-8, la représentation des horodatages, le traitement de null et le format des nombres. « Nous hachons le JSON » n'est pas une spécification, car l'ordre ordinaire des propriétés JSON n'est pas une propriété de sécurité.

Une entrée conceptuelle peut utiliser les champs suivants :

```json
{
  "journal_sequence": 8131,
  "event_id": "01JNRQ3M8W7P0Q4R6S9T1V2X3Y",
  "previous_hash": "sha256:9c7d...",
  "record_hash": "sha256:04b1...",
  "payload": {"event_type": "call.result_received"}
}
```

Une chaîne valide indique que les entrées conservées sont reliées sans modification indétectable, à condition que le vérificateur dispose de l'ancre de chaîne attendue. Elle ne prouve pas l'exhaustivité si un attaquant contrôle l'enregistreur et peut l'empêcher d'écrire un enregistrement. Ne présentez pas le chaînage par hachage comme une solution magique. Il rend les modifications visibles, mais ne peut pas enregistrer un événement que l'enregistreur n'a jamais observé.

Sallyport produit ses journaux Sessions et Activity à partir d'un même journal d'audit chiffré et chaîné par hachage. Sa commande `sp audit verify` vérifie la chaîne hors ligne sur le texte chiffré, sans nécessiter de clé du coffre. Cette conception relie la vue des sessions et celle des appels individuels à une même source ordonnée, au lieu de demander aux enquêteurs de rapprocher deux journaux distincts.

## Construisez une chronologie qui préserve l'incertitude

Une chronologie d'incident doit présenter séparément les faits, les observations et les résultats non résolus. Un récit soigné qui transforme les inconnues en verbes affirmatifs peut sembler utile pendant une analyse tendue, mais il crée un faux enregistrement que les preuves ultérieures peuvent contredire.

Supposons qu'un processus d'agent ait reçu une approbation à 09:00:00. Il a émis une commande SSH à 09:03:14. Le client a perdu sa connexion à 09:03:16. À 09:03:18, l'agent a utilisé HTTP pour interroger le système cible et a trouvé une configuration modifiée. Ces éléments étayent plusieurs explications : la commande SSH s'est terminée, un autre acteur a modifié l'état ou une tâche mise en file d'attente plus tôt a pris effet. La chronologie doit préciser quelle conclusion les preuves permettent d'établir et lesquelles elles ne permettent pas d'établir.

Utilisez ce format dans les notes d'incident :

| Ordre | Heure | Preuve | Affirmation étayée |
|---|---|---|---|
| 444 | 09:03:14.120Z | `call.dispatched` | La passerelle a envoyé la commande SSH à l'utilitaire. |
| 445 | 09:03:16.202Z | déconnexion du transport | La passerelle n'a reçu aucun code de retour. |
| 446 | 09:03:18.810Z | réponse à la requête HTTP | La configuration interrogée était différente à ce moment. |
| 447 | 09:03:19.001Z | `call.result_returned` | L'agent a reçu le résultat de la requête. |

Évitez d'écrire « la commande SSH a modifié la configuration » à moins de disposer d'une preuve directe reliant la commande à l'effet distant. Des journaux d'audit distants, un identifiant d'opération unique ou une réponse contenant un identifiant de requête durable côté serveur peuvent établir ce lien. Un horodatage proche ne le peut pas.

Les enquêteurs doivent aussi savoir ce que l'agent a vu lorsqu'il a pris ses décisions ultérieures. C'est pourquoi `result_returned` mérite son propre événement. Si la réponse distante est arrivée mais que l'agent s'est déconnecté avant de la recevoir, une action ultérieure de l'agent ne peut pas avoir suivi cette réponse. Si la réponse a atteint l'agent, elle peut expliquer une branche dangereuse de son comportement.

Présentez à la fois une voie de session et une voie d'appel dans la vue de l'incident. La voie de session montre les événements d'ouverture, d'approbation, de révocation, de verrouillage et de fermeture. La voie d'appel montre les événements d'acceptation, d'autorisation, d'envoi et de résultat. Une liste plate reste disponible pour la vérification, mais ces deux vues répondent à des questions différentes sans les mélanger.

## La gestion des secrets doit résister à l'analyse de l'incident

Les pistes d'audit échouent souvent au moment où elles deviennent les plus utiles, parce qu'une personne veut journaliser les en-têtes complets, les environnements shell et les corps de réponse « juste pour cette enquête ». Cette décision peut transformer un incident d'agent contenu en exposition d'identifiants.

Capturez l'identité de l'action sans le contenu secret. Pour HTTP, enregistrez la méthode, l'hôte et le chemin normalisés, la référence de l'identifiant ou le libellé de la clé, les noms d'en-têtes sûrs, le condensé de la requête, le statut de la réponse, l'identifiant de requête du prestataire lorsqu'il est présent et un résumé de réponse soigneusement choisi. N'enregistrez jamais un en-tête d'autorisation, une clé API brute, une clé privée ou un vidage complet de l'environnement. 

Pour SSH, enregistrez une référence d'hôte, la référence du compte si la politique l'autorise, une représentation normalisée de la commande, le condensé de la commande, l'état de la connexion et le code de retour lorsqu'il est reçu. Les commandes elles-mêmes peuvent contenir des secrets. Si votre flux autorise du texte shell arbitraire, utilisez un espace de preuves protégé pour les examens strictement autorisés, ou enregistrez uniquement une forme masquée accompagnée d'un condensé. Ne prétendez pas qu'un journal de commandes est inoffensif simplement parce qu'il ne contient pas de mots de passe.

Sallyport conserve les identifiants API et SSH dans son coffre chiffré et exécute l'action externe sans transmettre ces identifiants à l'agent. Cela supprime une raison fréquente pour laquelle une transcription d'agent et ses journaux deviennent un amas de secrets, mais la cible, le corps de la requête, les arguments de commande et la réponse peuvent toujours être sensibles.

Contrôlez séparément l'accès aux enregistrements bruts et la vérification. Un intervenant peut avoir besoin de vérifier une chaîne sans être autorisé à lire les détails chiffrés d'un appel. Un analyste sécurité peut avoir besoin des métadonnées de session et de cible, mais pas du contenu des charges utiles. Cette séparation rend la réponse aux incidents moins dépendante de la copie d'un journal complet dans une conversation, un ticket ou un tableur.

Lors de l'export des preuves, incluez la version du schéma, l'heure de l'export, la plage de séquences du journal, le résultat de la vérification et les règles de masquage utilisées. Conservez le journal protégé original selon ses contrôles habituels. Un export est une copie de travail, pas un remplacement de la preuve source.

## Testez l'enregistrement avec une exécution volontairement désordonnée

Une démonstration du parcours nominal ne prouve presque rien sur la reconstitution d'un incident. Testez les conditions qui rendent l'ordre ambigu : appels concurrents, réponses retardées, changements d'horloge, arrêts de processus, refus, révocations et expiration suivie d'une nouvelle tentative.

Menez un exercice contrôlé avec deux cibles externes autorisées. Faites attendre le premier appel avant son retour. Démarrez un deuxième appel après l'envoi du premier. Interrompez un troisième appel après son envoi. Révoquez ensuite la session et vérifiez que les appels suivants reçoivent un refus. Exportez le journal et remettez-le à un collègue qui n'a pas écrit le scénario.

Demandez à cet examinateur de répondre à cinq questions en utilisant uniquement l'export :

- Quel processus a reçu l'autorisation et quand celle-ci a-t-elle pris fin ?
- Dans quel ordre la passerelle a-t-elle accepté les appels de cette session ?
- Quels appels ont atteint la limite d'envoi ?
- Quel résultat l'agent a-t-il reçu avant chacun des appels suivants ?
- Quels résultats restent inconnus plutôt qu'échoués ou réussis ?

S'il doit vous demander la signification d'un champ, corrigez le schéma ou la documentation de l'export. S'il déduit un effet distant d'une expiration, corrigez les libellés de résultat. S'il ne peut pas distinguer une nouvelle tentative d'une nouvelle opération, ajoutez la relation et l'identifiant d'opération.

Conservez les artefacts de l'exercice. Ils deviendront des tests de régression lorsque vous modifierez une bibliothèque cliente, introduirez de la concurrence, ajusterez la conservation ou ajouterez un nouveau canal. Les problèmes d'ordre apparaissent souvent lors de refactorisations anodines, car les développeurs vérifient surtout que les actions fonctionnent encore tandis que le chemin de preuve modifie discrètement le moment de validation.

L'incident n'attendra pas une conception de journalisation plus propre. Attribuez une séquence de session lors de l'acceptation de l'appel, validez les événements du cycle de vie via un écrivain ordonné unique, préservez à la fois l'heure civile et le temps monotone, et laissez les résultats inconnus le rester. Ces choix donnent aux enquêteurs une séquence qu'ils peuvent défendre, plutôt qu'une chronologie qu'ils doivent constamment justifier.
