Lance l'optimiseur de $ETM_POWERSYNC_OPTIMIZER_CMD (défaut : la référence, mode normal) et y branche le vrai moteur : handshake direct accepté, GetPlan répondus sous 10 s, session entière conforme au contrat embarqué (règles sémantiques comprises), chaque plan appliqué sans fallbackCode, consigne hors bornes écrêtée et surcharge délestée par L4. Relais transparent pour capturer la session. README : la lancer contre un autre optimiseur. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
88 lines
5.1 KiB
Markdown
88 lines
5.1 KiB
Markdown
# tools/
|
|
|
|
Outils de développement et d'exploitation du plugin. Ce fichier décrit
|
|
`etm-powersync-trace-replay` et les deux outils du contrat du protocole optimiseur ;
|
|
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é.
|
|
|
|
```sh
|
|
# 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).
|
|
|
|
## Le contrat du protocole optimiseur — `etm-powersync-schema-check`, `etm-powersync-gen-protocol-doc`
|
|
|
|
Python 3, bibliothèque standard seule, aucun accès réseau. Le contrat :
|
|
`docs/etm-powersync-optimizer-protocol.openrpc.json` (OpenRPC 1.3), servi par le moteur
|
|
(`NymeaEnergy.GetOptimizerProtocol`).
|
|
|
|
```sh
|
|
# un message, une session NDJSON (les deux sens), des traces de décision
|
|
./tools/etm-powersync-schema-check --method GetPlan --params requete.json
|
|
./tools/etm-powersync-schema-check --method GetPlan --result plan.json --request requete.json --semantic
|
|
./tools/etm-powersync-schema-check --ndjson session.ndjson --semantic
|
|
./tools/etm-powersync-schema-check --trace etm-powersync-optimizer-trace-2026-10-17.ndjson --semantic
|
|
./tools/etm-powersync-schema-check --subset # le sous-ensemble de JSON Schema géré
|
|
|
|
# la prose du protocole, régénérée depuis le contrat ; --check : code 1 si pas à jour (ci-quality 5/5)
|
|
./tools/etm-powersync-gen-protocol-doc [--check]
|
|
# les listes fermées du contrat, régénérées depuis le CODE
|
|
ETM_POWERSYNC_CODE_LISTS=/tmp/listes.json <build>/tests/auto/protocolschema/etm-powersync-protocolschema \
|
|
testClosedListsAreGeneratedFromTheCode
|
|
./tools/etm-powersync-gen-protocol-doc --enums-from /tmp/listes.json
|
|
```
|
|
|
|
- **Sous-ensemble géré** : `$ref` local, `type`, `enum`, `const`, `properties`, `required`,
|
|
`additionalProperties`, `propertyNames`, `items`, `minItems`, `maxItems`, `minimum`, `maximum`,
|
|
`exclusiveMinimum`, `minLength`, `maxLength`, `pattern`, `oneOf`, `anyOf`, `allOf`. Tout autre
|
|
mot-clé est une erreur de schéma (code 2), jamais ignoré.
|
|
- **`--semantic`** applique `x-etm-semantic-rules` : ce que le validateur du moteur refuse en plus de
|
|
la forme, dans son ordre, sous le code qu'il publie (`fallbackCode`).
|
|
- **Code de sortie** : 0 conforme ; 1 écart de forme ou refus sémantique ; 2 erreur d'usage ou de
|
|
schéma.
|
|
- Conformité d'un optimiseur de bout en bout, avec le vrai moteur : suite
|
|
`etm-powersync-optimizer-conformance` (`tests/auto/conformance/README.md`).
|
|
|
|
Tests : `python3 -I tests/tools/etm-powersync-schema-check-test.py` et
|
|
`python3 -I tests/tools/etm-powersync-gen-protocol-doc-test.py`.
|
|
|