Patrick Schurig fb581218c8 feat(outils): etm-powersync-schema-check, validateur du contrat OpenRPC
Python, bibliothèque standard seule. Sous-ensemble de JSON Schema déclaré ;
un mot-clé non géré est une erreur de schéma, jamais ignoré. Valide un
message, une session NDJSON ou des traces ; --semantic applique
x-etm-semantic-rules dans l'ordre du validateur du moteur (une règle sans
implantation, ou l'inverse, est une erreur).

Test : références du sérialiseur et traces réelles du moteur conformes ;
optimiseur de référence mode par mode, et qui rejette chaque mode mauvais.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 21:15:51 +02:00
..

tools/

Outils de développement et d'exploitation du plugin. Ce fichier ne décrit que etm-powersync-trace-replay ; l'optimiseur de référence a le sien (etm-powersync-ref-optimizer/README.md), les autres scripts portent leur mode d'emploi en en-tête.

Noms d'optimiseur : powersync-optimizer = exemple de référence GPL (ce dépôt) ; etm-optimizer = optimiseur ETM (propriétaire, hors de ce dépôt). L'optimiseur de référence s'annonce powersync-optimizer au handshake ; son fichier garde le préfixe des artefacts.

etm-powersync-trace-replay — rejouer des traces de décision

Python 3, bibliothèque standard seule, GPL-3.0 comme le dépôt.

Le moteur écrit, quand le réglage optimizerTrace est activé (NymeaEnergy.SetOptimizerTrace, défaut : désactivé), une ligne NDJSON par cycle dans <storagePath>/etm-powersync-optimizer-trace-AAAA-MM-JJ.ndjson (format : INTERFACE.md, « Traces de décision » ; protocole : docs/OPTIMIZER_PROTOCOL.md annexe D). L'outil renvoie chaque request d'un de ces fichiers à un optimiseur et compare ses actions au plan enregistré.

# optimiseur local (défaut : unix:///run/powersync/optimizer.sock)
./tools/etm-powersync-trace-replay etm-powersync-optimizer-trace-2026-10-17.ndjson

# optimiseur sur le LAN, avec token, échec si une action diffère
./tools/etm-powersync-trace-replay trace.ndjson --endpoint tcp://nas:7600 \
    --token-file ~/.config/etm-optimizer.token --fail-on-divergence
  • Token : seulement par --token-file (jamais en argument : il se verrait dans ps). Il n'est ni affiché ni écrit.
  • Sorties : <trace>.replay-<horodatage>.ndjson (une ligne par requête rejouée : réponse, latence, écarts) et ….summary.txt, à côté de la trace. Jamais d'écrasement (--out vers un fichier existant est refusé).
  • Comparaison : charge, kind, puissance d'une consigne (setpoint, à --tolerance-w près), état d'une action state — la puissance d'une action state n'est pas comparée (le §6 ne la définit pas, et le plan du rule-based tracé la porte).
  • Résumé : requêtes rejouées, taux d'abstention, computeMs médian et max (s'il est fourni dans diagnostics), cycles non comparables (réponse enregistrée en erreur), cycles dont les actions du créneau courant diffèrent du plan enregistré, avec la liste.
  • Code de sortie : 0 ; 1 avec --fail-on-divergence s'il y a divergence ; 2 sur erreur (fichier, connexion, handshake refusé).
  • Les lignes L2 (strategy: "none") n'ont pas de requête : elles ne sont pas rejouées.

Les traces contiennent des mesures du site : elles restent sur le site. L'export est manuel (copie du fichier par l'installateur) ; l'outil ne parle qu'à l'endpoint donné.

Test : python3 -I tests/tools/etm-powersync-trace-replay-test.py (serveur de test minimal qui renvoie les réponses enregistrées — ce n'est pas l'optimiseur de référence).