Datasets
Un dataset est une collection nommée de données de référence. C'est ce qui donne aux logs générés leur contenu : sans lui, un template rendrait des valeurs vides.
Deux natures cohabitent, parce qu'elles s'éditent de la même façon — une collection ordonnée d'enregistrements — et ne diffèrent que par le schéma appliqué à chaque enregistrement.
Pool d'échantillons
Les données injectées dans les templates. Le moteur y tire un enregistrement à chaque événement généré, et les clés présentes alimentent la palette de l'éditeur.
[
{ "process": "chrome.exe", "pid": 4412 },
{ "process": "svchost.exe", "pid": 890 }
]
Un pool appartient soit à une technologie, soit à personne — il est alors partagé et n'importe quel message type peut le désigner.
Les enregistrements ne sont pas forcément plats : le corpus source contient des tableaux et des
objets imbriqués, qu'un template atteint par la notation pointée (sample.answers[0].data).
Population
Un jeu d'entités fictives, réunissant ses quatre natures dans un seul dataset — exactement
comme un config de l'ancien projet désignait le même nom de fichier dans conf/users/,
conf/servers/ et conf/web/ —, plus un cinquième groupe, les rôles, qui dit ce que chacune
a d'installé.
{
"users": [{ "name": "maurice.moss", "email": "maurice.moss@reynholm.com" }],
"servers": [{ "name": "SRV-RDP-01", "ip": "192.168.2.10" }],
"websites": [{ "host": "www.reynholm.com", "domain": "reynholm.com", "site_role": "marketing" }],
"sites": [{ "city": "Paris", "country": "FR", "egress_ip": "193.51.110.149" }],
"roles": [
{ "subject": "USER", "name": "*", "applications": ["microsoft-edge", "microsoft-365-apps"] },
{ "subject": "USER", "name": "IT Services", "applications": ["putty", "keepass"] },
{ "subject": "SERVER", "name": "database", "applications": ["microsoft-sql-server"] }
]
}
Les clés sont celles que les templates attendent : user.desktop_ip, server.agent_id,
website.site_role. Le tableau d'édition affiche donc littéralement ce que le template verra.
Le site géographique, et les deux adresses publiques
Un site est le bureau d'où sortent les employés d'une ville : sa egress_ip est l'adresse que
tous partagent, comme derrière un vrai NAT d'entreprise. Il rejoint l'utilisateur par sa
geo.city — aucune clé à ajouter aux utilisateurs. Une ville qui ne désigne aucun site est
signalée en avertissement, parce que c'est le mode de panne silencieux d'une jointure sur du texte
libre.
user.desktop_public_ip n'est donc pas « l'adresse vue depuis Internet » : c'est
site.egress_ip qui l'est. C'est l'adresse d'où le poste sort quand il n'est pas au bureau —
domicile ou réseau mobile —, celle qu'un geste marqué hors bureau fait
apparaître.
user.desktop_ip, la troisième, est l'adresse du poste sur le réseau interne. Elle n'est pas
décorative : c'est elle que nomme le journal d'une machine de l'entreprise que le poste joint — un
4624 de session distante, un ticket Kerberos, un accès à un partage. Ces journaux sont écrits par la
machine jointe, qui ne voit jamais le NAT du bureau ; y annoncer l'adresse publique mettait un
nom de poste NetBIOS à côté d'une adresse d'Internet, dans un message adressé à un serveur en 10.x.
Elle est redérivée à l'import, et pour une raison précise : les valeurs de l'ancien projet
tombaient dans le même /16 que l'adresse de sortie du bureau — c'est de ce champ-là que les plages
de sortie avaient été relevées —, si bien qu'un télétravailleur aurait été indiscernable d'un
employé au bureau. Deux populations portaient même des adresses CloudFront, Cloudflare et Google
présentées comme celles d'un employé. La dérivation est déterministe : un db:seed ne rejoue pas
les adresses. Un pays hors catalogue garde la valeur importée — on ne fabrique pas un domicile
français à un salarié islandais.
Une population sert dès aujourd'hui à l'aperçu : le sélecteur « rendre avec » de l'éditeur de template propose ses utilisateurs à la place des fixtures.
Une entité incomplète est acceptée, pas refusée
Le corpus source contient une population dégradée — demo-msn-webinar ne fournit que 9 des
19 clés utilisateur. La refuser rendrait son import impossible ; l'accepter en silence laisserait
des templates rendre vide. Elle est donc acceptée avec un avertissement listant les clés
absentes, affiché sur la page du dataset.
Seule la clé d'identité est obligatoire : name pour un utilisateur ou un serveur, host pour
un site.
Une population vit quelque part
Une population porte un fuseau horaire (carte « Métadonnées »), et c'est lui qui décide de
l'heure à laquelle sa journée se joue : une action réglée sur 08:00 dans un archétype a lieu à
08:00 pour ces utilisateurs-là. Un fuseau IANA — Asia/Tokyo, America/New_York — et non un
décalage en heures : le décalage est résolu pour chaque jour simulé, donc l'heure d'été suit
toute seule.
Les bancs d'essai qui s'appuient sur cette population en héritent, et peuvent le surcharger au cas par cas. Sans réglage, c'est UTC. Un pool d'échantillons, lui, n'habite nulle part : l'écran ne propose pas le champ, et l'API le refuse.
Ce que chaque rôle installe
Un rôle liste les applications installées sur les postes d'une tranche de la population :
l'unité d'organisation d'un utilisateur (org.ou_name), le rôle d'un serveur (role).
Le nom * est le socle de la tranche — ce que tout poste, ou tout serveur, a —, que chaque
rôle complète. Un utilisateur d'IT Services a donc le socle et la liste d'IT Services ; un serveur
dont personne ne décrit le rôle n'a que le socle.
La liste sert à deux choses, et c'est la même liste pour les deux :
- l'inventaire logiciel la déclare — le système, puis exactement ces applications, avec les compagnons que leur installateur pose (Chrome apporte Google Update, Edge son service de mise à jour, Acrobat le sien). Installé n'est pas lancé : un serveur de bases de données déclare SQL Server alors qu'aucun de ses gestes ne le démarre ;
- les journaux ne lancent rien d'autre. Quand un geste nomme un processus — un navigateur, une application bureautique, une tâche de fond —, ce ne peut être qu'un binaire de Windows ou l'une de ces applications. Un poste de comptabilité ne lance plus AnyDesk si son rôle ne l'a pas. Aucun horodatage ne bouge : les gestes restent les mêmes, seul le binaire qu'ils nomment est choisi parmi l'installé.
Une application est une clé du catalogue, qui vit dans le code : microsoft-edge,
google-chrome, putty… Une clé que le catalogue ne connaît pas est refusée à l'enregistrement —
elle ne déclarerait rien et ne bornerait aucun processus, ce ne peut être qu'une faute de frappe.
Deux rôles qui apparient la même unité sont refusés aussi (R&D et R and D sont la même
unité) : un seul des deux jouerait.
Trois règles rendent la liste sûre à ajouter :
- une tranche qui ne déclare aucun rôle garde le comportement d'avant : son inventaire est ce que ses gestes peuvent lancer, et ses journaux sont inchangés au bit près. Déclarer un seul rôle de serveur ne vide pas les postes ;
- les postes Linux sont laissés de côté : les pools de processus du moteur sont Windows, la liste ne s'applique pas à eux, et leur inventaire se réduit à leur système ;
- un oubli se voit, il ne se tait pas : un rôle qui n'apparie personne, une unité ou un rôle de serveur qu'aucune entrée ne décrit, une application citée deux fois — chacun est un avertissement sur la page du dataset, et l'aperçu des assets nomme les rôles restés sans liste.
Les six populations de démonstration reçoivent leurs rôles au semis, en choix de modélisation : le corpus ne porte aucun inventaire où les lire. Ils ne s'ajoutent qu'à une tranche qui n'en a aucun, si bien qu'une liste éditée sur cet écran survit au semis suivant.
L'éditeur
Deux vues du même contenu — basculer d'onglet ne perd rien.
Onglet tableau
Une ligne par enregistrement, une colonne par clé. Les colonnes sont calculées depuis les enregistrements présents ; « + ajouter une colonne » en propose une nouvelle, qui ne se matérialise qu'à la première saisie.
Une valeur imbriquée (geo, org, answers) s'édite en JSON dans sa cellule.
Ce n'est pas la même chose que d'y mettre une chaîne vide : les templates distinguent les deux.
{{ sample.x | default('-') }} se déclenche sur l'absence de la clé, jamais sur "".
Pour une population, un filtre affiche une nature d'entité à la fois — les utilisateurs, serveurs et sites n'ont pas les mêmes colonnes.
Le filtre Rôle n'affiche pas un tableau mais une carte par rôle : une liste Tranche, un champ Unité ou rôle de serveur, et les applications du catalogue en cases à cocher — une liste saisie en JSON dans une cellule se casserait à chaque frappe. + Ajouter un rôle en pose un vierge : refusé tant qu'il n'a pas de nom, il reste à l'écran, refus au-dessus, pour qu'on puisse le saisir.
Un document refusé mais bien formé — une entrée qu'on vient d'ajouter, encore sans identité — garde son tableau : seuls un JSON invalide ou un groupe inconnu le mettent en attente.
Au-delà de 50 enregistrements, le tableau pagine. C'est rare : 247 des 258 fichiers du corpus en comptent moins de 100, mais neuf en portent plus de 500.
Onglet JSON
Le document entier, dans un éditeur de code. C'est ce contrôle que le formulaire soumet réellement — le tableau est une amélioration posée par-dessus. Sans JavaScript, l'édition passe donc par le JSON, qui reste pleinement fonctionnel.
Un JSON invalide est signalé sans écraser le travail en cours ; le tableau se met simplement en attente. C'est aussi là qu'une clé d'application hors catalogue serait refusée — les cases à cocher n'offrent que les connues.
Rattachement à un message type
Le lien est une clé étrangère, pas une convention de nommage : deux messages types qui
désignent le même dataset le partagent explicitement. Le corpus en contient le cas —
pull-request-create et pull-request-merge de GitHub ont des données identiques.
Conséquences :
- supprimer un dataset ne supprime pas les messages types qui l'utilisaient : ils repassent simplement sans données ;
- supprimer un message type ne supprime pas son dataset, qui reste une ressource nommée ;
- un message type recréé sous le même nom n'hérite de rien.
Un message type sans dataset est un état légitime : le rendu reçoit alors {}, et les
| default(…) du template font le reste.