veaf-tools doctor — format du bloc collable¶
Public visé : les développeurs des lots qui consomment la sortie de
doctor— l'analyse de journal (FEAT-SUPPORT-LOG-ANALYSIS) qui l'intègre à son propre bloc de rapport, et la prise en charge de signalement (FEAT-SUPPORT-BUG-INTAKE) qui le relit.Schéma :
veaf-tools-doctor/1. — 🇬🇧diagnostic-block.en.md.
Pourquoi un format¶
Le bloc voyage à travers Discord ou une issue GitHub, copié à la main par quelqu'un qui ne le relira pas, et il est relu par une machine à l'autre bout. Ce n'est donc ni un affichage ni un fichier : c'est un contrat, versionné, que ni le producteur ni les consommateurs ne peuvent changer seuls.
L'implémentation vit dans src/python/veaf-tools/veaf_libs/diagnostics.py, producteur
(DiagnosticReport.to_block) et lecteur (parse_block) dans le même module — pour qu'ils ne
puissent pas diverger — et le test d'aller-retour est dans
test/python/veaf_libs/test_diagnostics.py.
Structure¶
=== VEAF-TOOLS DOCTOR BEGIN ===
schema: veaf-tools-doctor/1
generated: 2026-09-05T09:39:29Z
tool.version: 6.19.0
...
--- recent-errors ---
2026-09-03 21:05:52,533 - veaf-tools - ERROR - Failed to evaluate time expression
Traceback (most recent call last):
ValueError: ...
--- recent-errors end ---
=== VEAF-TOOLS DOCTOR END ===
Trois règles, et rien d'autre :
- Le bloc est délimité par
=== VEAF-TOOLS DOCTOR BEGIN ===et=== VEAF-TOOLS DOCTOR END ===. Il arrive au milieu d'autre chose (un message, des barrières de code) : un lecteur cherche ces deux lignes, il ne suppose pas que le bloc commence à la première ligne. - Entre les deux délimiteurs, chaque ligne est
clef: valeur. La séparation se fait sur le premier:— une valeur peut en contenir d'autres (un chemin Windows, un horodatage). Une clef et une valeur tiennent sur une seule ligne : le producteur écrase tout saut de ligne par une espace, faute de quoi une valeur multi-lignes reviendrait sous la forme de deux champs, dont un que personne n'a écrit. - La section optionnelle encadrée par
--- recent-errors ---et--- recent-errors end ---contient du texte brut. Un enregistrement commence à une ligne d'en-tête (AAAA-MM-JJ HH:MM:SS,mmm - <logger> - <NIVEAU> -) ; tout ce qui suit lui appartient, ce qui permet à une trace d'appels de survivre entière.
Les champs¶
L'ordre est celui de FIELD_ORDER dans diagnostics.py, et il est stable.
| Clef | Exemple | Vaut unknown quand |
|---|---|---|
schema |
veaf-tools-doctor/1 |
jamais |
generated |
2026-09-05T09:39:29Z |
jamais |
tool.version |
6.19.0 |
le paquet n'est pas installé et le fichier de version est absent |
tool.packaging |
frozen ou source |
jamais |
tool.executable |
C:\Users\<user>\...\python.exe |
l'interpréteur ne se nomme pas |
tool.python |
3.13.15 |
jamais |
machine.os |
Windows-11-10.0.26200-SP0 |
la plateforme ne répond pas |
machine.locale |
fr_FR / cp1252 |
la locale n'est pas déterminable |
machine.free_space |
654.0 GB on D:\ |
le disque ne répond pas |
dcs.detected |
yes / no |
jamais |
dcs.version |
2.9.29.27278 |
DCS absent, ou bannière introuvable dans dcs.log |
dcs.variant |
stable, openbeta |
DCS absent |
dcs.write_dir |
C:\Users\<user>\Saved Games\DCS |
DCS absent |
dcs.log_age |
3 d |
DCS absent |
veaf.home |
C:\Users\<user>\.veaf |
le dossier ne peut pas être créé |
veaf.log |
present, 1.2 MB / absent |
l'accès échoue |
veaf.lua_modules |
37 |
l'inventaire n'est pas lisible |
Un champ inconnu vaut la chaîne unknown et jamais une chaîne vide : « absent » et « non
collecté » se lisent pareil pour un humain, et un consommateur doit pouvoir les distinguer.
Règles d'évolution¶
- Ajouter un champ est compatible : un lecteur lit ce qu'il connaît et ignore le reste. Le producteur fait déjà voyager un champ qu'il ne connaît pas.
- Retirer ou renommer un champ ne l'est pas, et impose de passer à
veaf-tools-doctor/2. - Un lecteur vérifie
schemaavant de parser. Un bloc portant un schéma inconnu est un bloc dont il ne peut rien supposer.
Un bloc reçu n'est pas une mesure¶
parse_block lit du texte arrivé par une issue publique ou un message Discord. N'importe qui peut
en taper un à la main. Le producteur garantit la forme (un champ = une ligne), jamais la
vérité d'une valeur : un consommateur qui agit sur tool.version traite une déclaration, pas
une lecture prise sur la machine. C'est un point de confiance, pas un détail d'analyse syntaxique —
FEAT-SUPPORT-BUG-INTAKE est le premier à passer la frontière.
Caviardage¶
Tout ce que produit doctor passe par veaf_libs.redaction.redact avant d'être affiché : nom
de compte → <user>, adresse IP routable (v4 et v6) → <ip>, adresse e-mail → <email>, jeton ou
mot de passe → <redacted>. Les adresses de bouclage sont conservées : elles ne portent rien de
personnel et disent quelque chose d'utile.
Deux règles asymétriques, et l'asymétrie est délibérée.
L'identité est sur-caviardée. Le nom de compte est remplacé partout où il apparaît, pas
seulement sous Users/ : il ressort dans un dossier temporaire (Temp\pytest-of-Prénom\), dans un
nom de machine, dans un vidage de variables d'environnement. Mesuré sur 1489 enregistrements
ERROR réels, il survivait 56 fois à un caviardage qui avait pourtant traité le chemin
d'origine trois segments plus tôt.
Les identifiants ne sont pas caviardés. Il n'y a pas de règle d'entropie ici, et c'en est
une décision : une première version remplaçait toute suite de 24 caractères ou plus mêlant lettres
et chiffres. Mesurée sur le même journal, elle a produit 74 substitutions et zéro identifiant
secret ; mesurée sur les fichiers de données du dépôt, elle capturait 169 GUID DCS et 493 autres
identifiants, dont HVAR_USN_Mk28_Mod4_Corsair et M261_INBOARD_DE_M151_C_M274. Autrement dit
unknown payload <redacted> : on garde « ça a planté » et on jette « sur quoi ». Un secret est donc
reconnu à son contexte (une affectation à une clef de type token, password, access_token,
client_secret…) ou à sa forme connue (préfixe de jeton GitHub, JWT, URL de webhook,
identifiants dans une URL). Une suite aléatoire sans étiquette ni forme connue passe, volontairement.
Le caviardage se fait à la production, pas à la publication : au moment de publier, c'est un autre
programme, sur une autre machine, et il est trop tard. Un consommateur peut repasser redact sur ce
qu'il reçoit — l'opération est idempotente — mais il ne doit pas compter dessus pour rattraper une
source non caviardée.