test(decisions): comparateur --sous-palier, seul ECO_FLOOR_GRID → ECO_FLOOR_BELOW_STAGE est admis
Retire le motif des niveaux « eco » portant l'un des deux codes et les confronte deux à deux : tout autre passage, ou un ECO_FLOOR_GRID aux paramètres modifiés, est un ÉCART. targetW, counts, progress du niveau restent comparés. Les changements sont listés par scénario et par charge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
30527b9373
commit
35808f17bd
@ -2,7 +2,8 @@
|
||||
# Comparateur « IDENTIQUE HORS MOTIFS » (correctifs moteur a et b, etm70).
|
||||
#
|
||||
# etm-powersync-compare-hors-motifs.py <attendu.ndjson[.xz]> <obtenu.ndjson[.xz]> [--cas <sortie.md>]
|
||||
# [--achat] [--strategie] [--lignes <sortie.txt>]
|
||||
# [--achat] [--strategie] [--sous-palier]
|
||||
# [--lignes <sortie.txt>]
|
||||
#
|
||||
# Un lot qui ne change QUE des motifs doit laisser tout le reste de la référence `decisions`
|
||||
# intact à l'octet près. Ce script retire de chaque ligne, et SEULEMENT d'elle :
|
||||
@ -15,6 +16,11 @@
|
||||
# change cette VALEUR PUBLIÉE sans toucher aux consignes doit passer ce mode-là.
|
||||
# Avec --strategie (brief 4 T6, décision du 2026-10-17), il ramène EN PLUS `plan.strategy`
|
||||
# `rule-based` à `rules` d'une ligne de plan direct : le renommage du plan rule-based, et lui seul.
|
||||
# Avec --sous-palier (lot éco sous palier, 2026-10-19), il retire EN PLUS le motif des niveaux
|
||||
# « eco » portant ECO_FLOOR_GRID ou ECO_FLOOR_BELOW_STAGE, puis les confronte deux à deux : seul
|
||||
# ECO_FLOOR_GRID → ECO_FLOOR_BELOW_STAGE est admis ; un ECO_FLOOR_GRID dont les paramètres
|
||||
# changent, ou tout autre passage, est un ÉCART. Le reste du niveau (targetW, counts, progress)
|
||||
# reste comparé.
|
||||
# Tout le reste — consignes, powerW, estimatedPowerW, états, relais, courants, budget, draw,
|
||||
# counts, niveaux et leurs motifs, avancement — doit être IDENTIQUE. Code 0 si c'est le cas,
|
||||
# 1 sinon (et le premier écart est montré). La liste des motifs qui changent est imprimée, ou
|
||||
@ -50,11 +56,23 @@ def sans_achat(niveau, charge, achats):
|
||||
achats.append((charge, prog.pop('purchasedWh', ABSENT)))
|
||||
|
||||
|
||||
def normaliser(ligne, achat=False, strategie=False):
|
||||
"""Rend (ligne sans motifs, [(charge, motif retiré)], [(charge, purchasedWh retiré)])."""
|
||||
ECO_SOUS_PALIER = ('ECO_FLOOR_GRID', 'ECO_FLOOR_BELOW_STAGE')
|
||||
|
||||
|
||||
def sans_motif_eco(niveau, cle_motif, charge, motifs_eco):
|
||||
motif = niveau.get(cle_motif)
|
||||
if niveau.get('level') == 'eco' and isinstance(motif, dict) \
|
||||
and motif.get('code') in ECO_SOUS_PALIER:
|
||||
motifs_eco.append((charge, niveau.pop(cle_motif)))
|
||||
|
||||
|
||||
def normaliser(ligne, achat=False, strategie=False, sous_palier=False):
|
||||
"""Rend (ligne sans motifs, [(charge, motif retiré)], [(charge, purchasedWh retiré)],
|
||||
[(charge, motif de niveau éco retiré)])."""
|
||||
d = json.loads(ligne)
|
||||
retires = []
|
||||
achats = []
|
||||
motifs_eco = []
|
||||
if strategie and d.get('src') == 'plan' and (d.get('plan') or {}).get('strategy') == 'rule-based':
|
||||
d['plan']['strategy'] = 'rules'
|
||||
if d.get('src') == 'cycle':
|
||||
@ -64,6 +82,8 @@ def normaliser(ligne, achat=False, strategie=False):
|
||||
sans_manque(n, 'decision')
|
||||
if achat:
|
||||
sans_achat(n, ch.get('loadId'), achats)
|
||||
if sous_palier:
|
||||
sans_motif_eco(n, 'decision', ch.get('loadId'), motifs_eco)
|
||||
elif d.get('src') == 'plan':
|
||||
for s in (d.get('plan') or {}).get('timeSlots', []) or []:
|
||||
for a in s.get('actions', []) or []:
|
||||
@ -72,7 +92,9 @@ def normaliser(ligne, achat=False, strategie=False):
|
||||
sans_manque(n, 'reason')
|
||||
if achat:
|
||||
sans_achat(n, a.get('loadId'), achats)
|
||||
return json.dumps(d, sort_keys=True, ensure_ascii=False), retires, achats
|
||||
if sous_palier:
|
||||
sans_motif_eco(n, 'reason', a.get('loadId'), motifs_eco)
|
||||
return json.dumps(d, sort_keys=True, ensure_ascii=False), retires, achats, motifs_eco
|
||||
|
||||
|
||||
def achat_court(v):
|
||||
@ -100,6 +122,7 @@ def main():
|
||||
sortie_lignes = sys.argv[sys.argv.index('--lignes') + 1] if '--lignes' in sys.argv else None
|
||||
achat = '--achat' in sys.argv
|
||||
strategie = '--strategie' in sys.argv
|
||||
sous_palier = '--sous-palier' in sys.argv
|
||||
lignes_changees = []
|
||||
|
||||
if len(attendu) != len(obtenu):
|
||||
@ -112,15 +135,25 @@ def main():
|
||||
if a == b:
|
||||
brutes_identiques += 1
|
||||
continue
|
||||
na, ra, aa = normaliser(a, achat, strategie)
|
||||
nb, rb, ab = normaliser(b, achat, strategie)
|
||||
na, ra, aa, ea = normaliser(a, achat, strategie, sous_palier)
|
||||
nb, rb, ab, eb = normaliser(b, achat, strategie, sous_palier)
|
||||
lignes_changees.append((i, a, b))
|
||||
if na != nb:
|
||||
if na != nb or len(ea) != len(eb):
|
||||
print(f'ÉCART HORS MOTIFS{" ET HORS ACHAT" if achat else ""}'
|
||||
f'{" ET HORS STRATÉGIE" if strategie else ""} à la ligne {i} :')
|
||||
f'{" ET HORS STRATÉGIE" if strategie else ""}'
|
||||
f'{" ET HORS MOTIF ÉCO SOUS PALIER" if sous_palier else ""} à la ligne {i} :')
|
||||
print('- ' + a[:3000])
|
||||
print('+ ' + b[:3000])
|
||||
return 1
|
||||
# Le motif d'un niveau éco : identique, ou ECO_FLOOR_GRID devenu ECO_FLOOR_BELOW_STAGE.
|
||||
for (charge, ma), (_, mb) in zip(ea, eb):
|
||||
if ma == mb:
|
||||
continue
|
||||
if (ma.get('code'), mb.get('code')) != ECO_SOUS_PALIER:
|
||||
print(f'ÉCART DE MOTIF ÉCO à la ligne {i} ({charge}) : {ma} → {mb}')
|
||||
return 1
|
||||
cas[(json.loads(a).get('fn'), charge, f'niveau éco {ma["code"]}',
|
||||
f'niveau éco {mb["code"]}')] += 1
|
||||
fn = json.loads(a).get('fn')
|
||||
for (charge, ma), (_, mb) in zip(ra, rb):
|
||||
if ma != mb:
|
||||
@ -134,10 +167,11 @@ def main():
|
||||
if sa != sb:
|
||||
cas[(fn, '(plan)', f'strategy {sa}', f'strategy {sb}')] += 1
|
||||
# Le manque d'un niveau change sans que le motif de tête change : à dire aussi.
|
||||
elif ra == rb and aa == ab:
|
||||
elif ra == rb and aa == ab and ea == eb:
|
||||
cas[(fn, '(niveau)', 'missingWh', 'missingWh corrigé')] += 1
|
||||
|
||||
hors = 'HORS MOTIFS' + (' ET HORS ACHAT' if achat else '') + (' ET HORS STRATÉGIE' if strategie else '')
|
||||
hors = ('HORS MOTIFS' + (' ET HORS ACHAT' if achat else '') + (' ET HORS STRATÉGIE' if strategie else '')
|
||||
+ (' ET HORS MOTIF ÉCO SOUS PALIER' if sous_palier else ''))
|
||||
print(f'IDENTIQUE {hors} : {len(attendu)} lignes, dont {brutes_identiques} identiques '
|
||||
f'à l\'octet et {len(attendu) - brutes_identiques} qui ne diffèrent que par '
|
||||
f'{"les motifs" + (", purchasedWh" if achat else "") + (" ou plan.strategy" if strategie else "")}')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user