Skip to content

Add "Explore the Day" feature: map-based grid analysis with daily activity ranking#109

Merged
marota merged 30 commits into
mainfrom
claude/tender-lovelace-1yrtx2
Jun 26, 2026
Merged

Add "Explore the Day" feature: map-based grid analysis with daily activity ranking#109
marota merged 30 commits into
mainfrom
claude/tender-lovelace-1yrtx2

Conversation

@marota

@marota marota commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a comprehensive "Explore the Day" feature to the manoeuvre IHM that enables users to visualize grid activity across a full day. The feature loads three snapshots (midnight, noon, 23:00), identifies the most active substations based on switching changes, and displays them on an interactive map with geographic coordinates.

Key Changes

New Modules

  • manoeuvre/dataset/exploration.py — Core day exploration logic (Python-pure, testable without pypowsybl):

    • extraire_etats_kinds() / structure_reseau() — Extract switch states and network structure from pypowsybl networks
    • changements_par_vl() — Count switching changes per voltage level across three time snapshots, ventilated by switch type (BREAKER/DISCONNECTOR/LOAD_BREAK_SWITCH)
    • agreger_par_poste() / classer_postes() — Aggregate changes by substation and rank by activity
    • vl_le_plus_actif() — Identify the most active voltage level per substation
  • manoeuvre/dataset/geographie.py — Geographic coordinate resolution (chaîne de sources):

    • positions_xiidm() — Extract coordinates from pypowsybl substationPosition extension (if present)
    • charger_snapshot() — Load committed snapshot (data/postes_rte_geo.json) indexed by substation_id
    • fetch_odre_records() — Fetch ODRE dataset (postes-electriques-rte) with local caching
    • apparier_odre() — Best-effort matching of ODRE records to substation IDs via normalized mnemonics (handles prefix fallback, name-based matching)
    • resoudre() — Coordinate resolution chain: XIIDM → snapshot → ODRE (with fallback to list-only view if all fail)
    • Tolerant geo-field extraction supporting multiple ODRE formats (geo_point_2d, GeoJSON, etc.)

IHM Backend (scripts/manoeuvre_ihm.py)

  • DayExploration class — Holds exploration state (3 hourly snapshots, switch states per VL, substation rankings, coordinates)
  • construire_exploration(date, heures) — Orchestrates loading, state extraction, change calculation, and coordinate resolution
  • Session.load_states(vl, states) — Load a poste with explicit switch states (for viewing topology at a specific hour without reloading full network)
  • Session.set_target_states(states) — Set target topology from another hour's state
  • New endpoints:
    • POST /api/explore_day — Trigger exploration, return payload with rankings, change counts, coordinate stats
    • GET /api/explore_coords_file — Download resolved coordinates as JSON (for committing to data/postes_rte_geo.json)
    • POST /api/explore_poste — Load a poste's topology at a specific hour
    • POST /api/explore_retain_target — Retain another hour's topology as the target

IHM Frontend (scripts/manoeuvre_ihm_assets/index.html)

  • Map pane (#mapPane) — Full-screen SVG-based map with:

    • Web Mercator projection of substations (disks colored by voltage level)
    • Zoom (mousewheel) and pan (drag) interactions
    • Hover/click bubbles showing substation details (name, voltage, change counts by type, voltage levels)
    • Legend and loading spinner
    • Right sidebar listing top-10 most active substations (clickable)
    • Golden halo highlighting top-10 substations
  • Explore bar (#exploreBar) — Context bar when viewing a poste from the map:

    • Shows current substation and hour
    • Buttons to select departure hour and retain target from other hours
    • Seamless toggle between map and topological views
  • **

https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa

claude added 30 commits June 25, 2026 09:46
… intérêt

Onglet RTE7000 : après le choix d'une date, le bouton « 🗺 Explorer la journée »
charge 3 situations (minuit / midi / 23 h), cartographie les postes France et met
en évidence les 10 postes les plus actifs de la journée.

- exploration.py (nouveau) : nombre d'OC dont l'état change sur la journée, par
  poste, ventilé par type d'OC (DJ / SA / interrupteur). Cœur Python pur.
- geographie.py (nouveau) : coordonnées par chaîne de sources (substationPosition
  embarquée → snapshot data/postes_rte_geo.json → ODRE en direct, échec rapide).
  Le dataset RTE 7000 ne porte pas de coordonnées ; scripts/fetch_postes_geo.py
  génère le snapshot hors-ligne (apparie codes ODRE ↔ substation_id, mesure le taux).
- Carte SVG autonome (sans tuiles ni lib externe), disques colorés par tension,
  projection Web Mercator, zoom/déplacement par viewBox (~6000 postes). Clic →
  bulle ; double-clic → vue topologique du poste avec barre Départ/Cible 00h/12h/23h
  (heure et champ poste synchronisés). Sans coordonnées : classement en liste.
- Endpoints /api/explore_day, /api/explore_poste, /api/explore_retain_target.
- Tests : test_exploration.py, test_geographie.py, test_ihm_explore.py.
  Doc : docs/manoeuvre_ihm.md (§ 1ter).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
… persistance

Sur le Space HuggingFace (sortie internet autorisée), l'appariement ODRE
(postes-electriques-rte ↔ substation_id) se fait désormais automatiquement dès la
1ʳᵉ exploration, sans étape hors-ligne préalable :

- geographie.resoudre : fetch ODRE generous-but-bounded (403 = refus, non retenté
  → échec rapide si bloqué, sans pénaliser l'exploration), persistance de
  l'instantané résolu (data/postes_rte_geo.json) → explorations suivantes via le
  snapshot (sans re-fetch), stats d'appariement remontées (taux affiché).
- ecrire_snapshot (nouveau) ; toggle MANOEUVRE_ENABLE_ODRE.
- Endpoint GET /api/explore_coords_file + bouton « ⬇ coordonnées » : télécharger
  l'instantané persisté pour le committer une fois (FS du Space éphémère).
- En-tête de carte : source + taux d'appariement ODRE.
- Tests : persistance + snapshot prioritaire, 403 non retenté, endpoint de
  téléchargement, champs coord_stats/coord_file du payload.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
- MANOEUVRE_GEO_SNAPSHOT : chemin de l'instantané de coordonnées configurable
  (par défaut data/ en local ; le Dockerfile le pointe sur le cache inscriptible,
  adossable au stockage persistant HF pour survivre aux redémarrages).
- Dockerfile : env MANOEUVRE_GEO_SNAPSHOT + commentaire (sortie ODRE ouverte sur
  les Spaces → rien à configurer ; persistance via /data ; toggle/ token).
- SETUP.md : table d'env (MANOEUVRE_ENABLE_ODRE, ODRE_TOKEN, MANOEUVRE_GEO_SNAPSHOT)
  + section « Explorer la journée » (ODRE auto, persistance, mémoire 3 réseaux,
  repli liste si appariement nul).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…riable)

L'instantané des coordonnées (carte « Explorer la journée ») est par défaut placé
DANS le cache (DGITT_CACHE_DIR/postes_rte_geo.json). Ainsi, pointer simplement
DGITT_CACHE_DIR sur le stockage persistant HF (=/data/dgitt) fait survivre aux
redémarrages à la fois les instantanés XIIDM ET les coordonnées — une seule
variable. MANOEUVRE_GEO_SNAPSHOT reste disponible pour forcer un autre chemin.
Retrait de la valeur codée en dur du Dockerfile ; SETUP.md mis à jour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
La carte restait vide (« coord. : aucune ») sans dire pourquoi. Ajout d'un
diagnostic et d'un appariement plus robuste :

- apparier_odre : index ODRE **par code ET par nom** (mnémonique normalisé),
  match exact (code puis nom) puis repli préfixe (≥ 4 car.) — couvre le cas où
  ODRE n'expose qu'un nom (CONCARNEAU) là où le réseau porte un mnémonique
  (CONCA). Stats enrichies : n_odre, sample_fields/codes/noms/subs/non_apparies.
- resoudre : capture odre_error (injoignable) vs 0 apparié dans stats_out.
- construire_exploration : journalise coord_stats (logs du Space).
- Front : quand la carte est vide, affiche le diagnostic — ODRE injoignable
  (erreur) ou joignable mais 0 apparié (échantillons champs/codes/noms vs subs)
  → permet d'ajuster _CLES_CODE/_CLES_NOM.
- Tests : appariement par nom + préfixe, diagnostic « 0 apparié ».

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…de brut

Diagnostic confirmé : ODRE est joignable mais l'export json/csv ne porte QUE les
attributs (code_poste, nom_poste, tension…), PAS la géométrie → 0 apparié. Et les
code_poste recoupent ~98 % des substation_id RTE (vérifié : 4717/4811 sur
l'instantané 2021-01-01).

- fetch_odre_records : interroge désormais l'export **geojson** (qui porte la
  géométrie), aplatit chaque feature en record + geo_point_2d (centroïde via
  _centroid, gère Point/Polygon/Multi). Cache renommé odre_postes_geo.json
  (ignore l'ancien cache sans géométrie).
- apparier_odre : match sur **code_poste brut (verbatim)** d'abord (98 %), puis
  code normalisé, puis nom, puis préfixe.
- Tests : fetch geojson + centroïde, match code brut, _centroid.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
Diagnostic confirmé : le dataset ODRE postes-electriques-rte est **tabulaire sans
géométrie** (vérifié via l'API records) — inutilisable pour la carte. Bascule des
coordonnées sur deux sources qui MATCHENT le substation_id :

- **Plan de masse RTE committé** (manoeuvre/dataset/grid_layout_rte.json, par VL,
  fourni) : source **primaire, hors-ligne, ~98 %** des postes (4723/4811 vérifié)
  → carte affichée **sans configuration ni accès réseau**. positions_from_layout
  agrège par poste (VL de plus haute tension) ; coords planaires projetées
  côté serveur (y inversé pour l'écran), Mercator pour les sources lon/lat.
- **OSM/Overpass** en repli (fetch_osm_substations) : ref:FR:RTE = substation_id
  (vérifié : recoupement quasi total), lat/lon. Persisté + téléchargeable.
- apparier_odre : match code brut + normalisé + nom + préfixe (générique).
- Payload carte : x,y (prêtes écran) au lieu de lon/lat ; coord_source ∈
  {layout, osm, snapshot, xiidm, aucune} ; diagnostic enrichi.
- Packaging : grid_layout_rte.json en package-data ; toggles MANOEUVRE_ENABLE_OSM
  / MANOEUVRE_GEO_LAYOUT. Dockerfile/SETUP.md/CHANGELOG/docs à jour.
- Tests : positions_from_layout, charger_layout (bundle), merc, fetch OSM, chaîne.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…ar VL, heure

Suite aux retours sur la carte (« Explorer la journée ») :

- **Disques agrandis** (lisibilité : les 1 px étaient flous) — base ≈ ancienne
  taille des top ; les **10 mis en évidence** sont encore plus gros + halo.
- **Fond détourant la France** : enveloppe convexe (« Hexagone ») du nuage de
  postes (même repère, sans donnée externe), sur un fond « mer » bleu pâle.
- **Classement & mise en évidence au niveau voltage level** (granularité fine,
  plus par site) : `_explore_payload` classe les VL actifs ; un poste est haloé
  s'il porte un VL du top-10 (rang = meilleur VL). Le panneau liste les VL.
- **Sélecteur d'heure sur la carte** (en-tête 00 h/12 h/23 h) : choisit l'heure de
  la topologie ouverte au double-clic / clic sur un VL actif.
- Tests/doc/CHANGELOG à jour (jetons carte, classement par VL).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…carts départ/cible

- Orientation : le plan de masse RTE ayant déjà le nord en haut (y vers le sud),
  disques et fond de carte servis sans inversion d'axe (seules les sources
  lon/lat OSM restent inversées en Web Mercator). Corrige le rendu « à l'envers ».
- Fond de carte committé (france_basemap.json) : frontières départements +
  pays voisins pré-projetées dans le repère du plan de masse
  (scripts/build_france_basemap.py, charger_basemap, GET /api/explore_basemap),
  embarqué dans le package.
- Légende des tensions filtrante : clic sur une bande affiche/masque les disques
  correspondants ; boutons « tout » / « aucun » (voltToggle, voltAll, voltBand,
  MAP.voltOff).
- Écarts départ/cible mis en évidence en vue topologique : vert = fermé à la
  cible (était ouvert), orange = ouvert à la cible, sur les deux schémas
  (Session.diff_states → champ `changes` des réponses ; highlightChanges,
  classes .octog-closed / .octog-opened). Recalculé à chaque bascule d'organe,
  changement d'heure ou rétention de cible.
- Tests : diff départ/cible (test_ihm_explore), fond de carte (test_geographie),
  jetons front-end. Docs + CHANGELOG mis à jour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…only flashy, heure cible

Affine la vue « Explorer la journée » suite aux retours :

- Re-groupements de nœuds (scissions/fusions) comptabilisés : au-delà des OC,
  le décompte intègre le nombre minimal d'ouvrages séparés dans un nouveau nœud
  ou ayant rejoint un nœud (extraire_structure_topo + partition_ouvrages +
  distance de transfert noeuds_deplaces, max sur transitions dans
  changements_nodaux_par_vl, intégré au total via fusionner_nodaux). Affiché :
  badge ⚇ dans le classement, ligne dédiée dans la bulle.
- Écarts départ/cible : mis en évidence UNIQUEMENT sur le schéma cible, en
  couleurs vives (vert flashy = fermé à la cible, orange flashy = ouvert).
- Heure cible surlignée en bleu dès l'ouverture d'un poste (cible = départ).
- Pays voisins assombris sur le fond de carte (contraste avec les zones
  maritimes).

Tests : partition/distance de transfert/agrégation nodale (pures + réseau de
réf.), nodal exposé par le payload, jetons front-end. Docs + CHANGELOG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…son fourni)

Nouveau document docs/manoeuvre_carte_geographique.md décrivant le pipeline
complet de la carte « Explorer la journée » à partir du plan de masse RTE
fourni : format/nature du grid_layout.json, agrégation par poste
(positions_from_layout, VL de plus haute tension), chaîne de résolution
(layout primaire → snapshot → OSM), projection écran (_xy : plan de masse tel
quel car nord en haut, lon/lat en Web Mercator inversé), fond de carte calibré
(build_france_basemap.py : ajustement affine lon/lat → repère du plan de masse),
rendu front (buildMap : disques par tension, fond vs enveloppe convexe, zoom),
dégradation gracieuse, régénération, limites.

Liens croisés depuis docs/manoeuvre_ihm.md (§1ter) et CHANGELOG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
Zones maritimes franchement bleues (#a3c9ec) et départements France en blanc
(#fcfcfa) → contour côtier net ; pays voisins en gris neutre (#c3c9d0),
distincts de la mer et de la France.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…e cible au changement de tension

- Décompte des re-groupements de nœuds : les ouvrages ISOLÉS (déconnectés —
  composante sans jeu de barres) ne sont plus comptés comme des nœuds. La
  structure relève les jeux de barres (extraire_structure_topo → 'barres') ;
  partition_ouvrages exclut les composantes sans barre ; noeuds_deplaces ne
  considère que les ouvrages en service dans les deux situations. Corrige
  l'inflation (ex. ⊝7 dû à des ouvrages déconnectés). Le décompte des OC
  (DJ+SA+INT) sur la journée est inchangé (choix utilisateur).
- Changement de niveau de tension d'un poste : l'heure de départ ET l'heure cible
  retenue sont conservées (cible ré-appliquée sur le nouveau VL) au lieu de
  réinitialiser la cible au départ — mapToTopo(sub, vl, hour, cibleHour).
- Tests : partition/changements nodaux ignorant les isolés ; structure 'barres'.
  Docs + CHANGELOG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…uvrages isolés

Le badge « X nœud(s) » (départ/cible/étape) et la ligne « obtenu/visé » comptent
désormais les nœuds RÉELS (composantes avec jeu de barres ; _nb_noeuds_reels) —
les ouvrages isolés (déconnectés) ne sont plus comptés comme nœuds, cohérent avec
l'éditeur nodal qui les présente à part. AFFICHAGE uniquement : le moteur de
séquencement garde TopologieNodale.nb_noeuds (isolés inclus, requis p. ex. en
mise en service) et le verdict de réalisabilité est inchangé.

Test : _nb_noeuds_reels ≤ nb_noeuds, strict quand des ouvrages sont isolés.
CHANGELOG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…cherche en mode carte

- Régression corrigée : sélectionner un poste via le champ de recherche (ou la
  liste) quitte la carte et affiche sa topologie (load() appelle exitMapMode) —
  auparavant la topologie restait cachée derrière la carte.
- Nom de scénario par défaut formaté (recalculé tant que non édité par l'utilisateur,
  défaut auto sinon) :
  - RTE7000 : poste_AAAAMMJJ_hDepart_topoDepart{n}Noeud_hCible_topoCible{n}Noeud_(observee|modifiee)
    (observee = cible = topologie observée à l'heure cible ; modifiee = éditée).
  - Local : poste_topoDepart{n}Noeud_topoCible{n}Noeud_nomFichier.
  Suivi de l'état (S.cibleModifiee) sur open/heure/rétention (observee) vs
  toggle/édition nodale (modifiee) ; S.scenNameDirty respecte une édition manuelle.

Vérifié au navigateur (noms RTE7000 + local conformes ; carte quittée à la
sélection). Jetons front-end testés. Docs + CHANGELOG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…escence

- Lint (ruff) : retrait des imports inutilisés (typing.Iterable dans
  exploration.py ; csv, io dans build_france_basemap.py) et éclatement des
  instructions multiples sur une ligne (E702).
- Docs : la réorganisation de main (docs/manoeuvre_ihm.md → docs/manoeuvre/ihm.md)
  a été intégrée ; déplacement de docs/manoeuvre_carte_geographique.md →
  docs/manoeuvre/carte_geographique.md et mise à jour des renvois croisés
  (ihm.md, carte_geographique.md, CHANGELOG, CLAUDE.md).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…le Hub)

Le déploiement pousse un snapshot orphelin de tout l'arbre vers le Space ; or
docs/ et data/ portent des PNG que le Hub HuggingFace refuse hors Xet/LFS
(ces dossiers ne sont de toute façon pas COPIés dans l'image — seuls
expert_op4grid_recommender/ et scripts/ le sont). Le workflow et le flux manuel
de SETUP.md retirent désormais docs/ data/ tests/ du snapshot → push binaire-free
et plus léger.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…us de l'élagage docs/data

Belt-and-suspenders : après l'élagage de docs/ data/ tests/, on retire aussi du
snapshot indexé d'éventuels binaires résiduels (venv*, *.prof, *.pptx) via
git rm -r --cached --ignore-unmatch (placé APRÈS git add -A pour être effectif ;
no-op si absents). Workflow + SETUP.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…branches claude/**)

Le workflow se déclenche désormais sur un push (main OU claude/**) qui touche
l'interface : scripts/manoeuvre_ihm.py, scripts/manoeuvre_ihm_assets/**, le module
expert_op4grid_recommender/manoeuvre/**, le Dockerfile, deploy/huggingface/** ou le
workflow lui-même. Les push doc/tests-only ne redéploient plus. Les branches de dev
donnent une preview live avant merge (le Space reflète la dernière branche poussée ;
re-pousser main le ramène à la prod). workflow_dispatch + concurrency « dernier gagne »
conservés. SETUP.md mis à jour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
… journée

Après « Explorer la journée », la liste de postes (champ de recherche +
présélection à gauche) était vide (« Aucun poste »), seule la liste des plus
actifs à droite était sélectionnable. Désormais :
- la liste est peuplée depuis le réseau de référence de l'exploration
  (populatePostes via /api/postes, juste après l'explore) ;
- sélectionner un poste (recherche ou présélection) pendant l'exploration l'ouvre
  à l'heure courante de la carte, comme un double-clic (selectPoste → mapToTopo si
  une journée est explorée, sinon load classique).

Vérifié au navigateur (liste peuplée, recherche filtrante, ouverture à l'heure
explorée + nom de scénario formaté). Jeton front-end testé. CHANGELOG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…tension, en fondu

La carte trace les lignes électriques entre postes, colorées par niveau de tension
et en fondu (trait fin non-scaling, faible opacité) sous les disques — visualiser
la structure du réseau sans gêner la lecture. Bascule « Lignes » dans la légende
(linesToggle / MAP.showLines), respectant aussi le filtre par tension.

- Backend : exploration.extraire_connexions(net, vl_meta) — lignes/liaisons reliant
  deux postes DISTINCTS, dédupliquées par couple + tension ; générique (local ou
  RTE7000). Exposé par le payload d'exploration (connexions, restreintes aux deux
  extrémités géolocalisées).
- Frontend : couche .conn dans buildMap, data-vb pour le filtre tension, toggle
  légende, CSS fondu.

Validé sur le réseau France réel (fichier RTE7000 fourni) : 6568 lignes tracées,
bascule masque/affiche OK. Tests : extraire_connexions (dédup, postes distincts),
payload (connexions géolocalisées), jetons front-end. Docs + CHANGELOG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…, disques restant dominants)

Opacité du tracé des lignes 0.17 → 0.32 (et largeur 0.8 → 0.9) : le maillage est
plus lisible tout en restant bien en retrait des disques (postes), qui gardent leur
opacité pleine et leur taille supérieure.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…erche, double-clic légende

1) Sauvegarde anti-doublon : si un scénario identique (même départ ET cible) existe
   déjà (name, name_0, name_1…) → non réécrit, utilisateur informé ; sinon nom rendu
   unique par index _0/_1… (Session.save_scenario → {status} ; plus d'invite
   écraser/renommer côté front).
2) Base de scénarios PARTAGÉE + recherche : dossier configurable
   (MANOEUVRE_SCENARIOS_DIR ; sous le cache → persistable /data sur le Space) alimenté
   par toutes les sauvegardes. Métadonnées calculées à la sauvegarde
   (Session.scenario_meta : tension, nb barres, nœuds départ→cible, OC DJ/SA/INT,
   ouvrages déplacés en changement de nœud). Modale « Recharger » = recherche
   filtrante (texte poste/nom + tension + seuils min barres/DJ/SA/INT/nœud) avec
   métadonnées par résultat (/api/scenarios renvoie des objets).
3) Légende tensions : double-clic isole un niveau (masque les autres) / réaffiche
   tout s'il est déjà seul (voltClick/voltDouble débounce).

Dockerfile + SETUP.md : MANOEUVRE_SCENARIOS_DIR/SEQUENCES_DIR. Vérifié au navigateur
(dedup+index, recherche filtrante, isolement légende). Tests + jetons front-end.
Docs + CHANGELOG. Suite manœuvre : 1034 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…r) + re-synchro au rechargement

- Chaque scénario logge sa date + heure de DÉPART : RTE7000 = date/heure choisies
  (depart_dt envoyé par l'IHM), local = horodatage du fichier (net.case_date).
  Session._date_tags en dérive année, saison (météo) et jour de semaine ; stockés
  dans meta + source (rte|local).
- Recherche : filtres année / saison / jour ajoutés à la modale ; chip date 📅
  par scénario.
- Rechargement RTE7000 : /api/load_scenario renvoie meta ; syncDepartFromScenario
  remet les sélecteurs Date/Heure en cohérence avec le scénario.

Vérifié au navigateur (tag dim·hiver, filtres, re-synchro 2099→2021-01-03/23:00).
Jetons front-end testés.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…ts + docs consolidées

- Téléchargement de TOUTE la base de scénarios en archive ZIP : GET
  /api/scenarios_archive (zipfile) + bouton « ⬇ Tout (zip) » dans la modale de
  rechargement (downloadAllScenarios).
- Tests (couverture accrue) : tags date/heure (RTE7000 depart_dt + local case_date,
  année/saison/jour), /api/load_scenario renvoie meta pour la re-synchro,
  /api/scenarios_archive (zip valide + métadonnées), en plus du dedup/index et de
  la recherche déjà couverts. Jetons front-end.
- Docs consolidées (docs/manoeuvre/ihm.md) : section « Réutiliser des scénarios »
  réécrite (base partagée, anti-doublon/index, recherche par métadonnées + date,
  re-synchro, export zip) ; format de fichier scénario enrichi du bloc `meta` ;
  table API HTTP mise à jour (scenarios/save/load_scenario/scenarios_archive).

Suite manœuvre : 1037 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…cascade)

Les dossiers scénarios/séquences dérivent désormais du cache si leur variable
dédiée n'est pas fixée (_cache_subdir) : régler le seul DGITT_CACHE_DIR=/data/dgitt
fait cascader scenarios/, sequences/ et les coordonnées sur le stockage persistant.
Dockerfile allégé (plus de MANOEUVRE_SCENARIOS_DIR/SEQUENCES_DIR codés en dur).
SETUP.md : section « Persistance /data » pas-à-pas + table à jour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…gements

Les journées téléchargées (instantanés XIIDM du dataset RTE 7000) ne doivent
plus encombrer le stockage persistant /data : elles sont volumineuses et
régénérables à la demande. On sépare désormais deux espaces distincts :

- DGITT_CACHE_DIR : cache des instantanés téléchargés → éphémère par défaut
  (ne pas mettre sur /data).
- MANOEUVRE_DATA_DIR : données à conserver (base partagée de scénarios +
  séquences + coordonnées résolues) → à pointer sur le stockage persistant.

`_persist_root()` résout MANOEUVRE_DATA_DIR, à défaut DGITT_CACHE_DIR
(rétro-compatibilité : l'ancienne config mutualisait tout dans le cache),
sinon None. `_persist_subdir()` (ex-`_cache_subdir`) cascade dessus pour les
scénarios, séquences et l'instantané de coordonnées (GEO_SNAPSHOT).

Dockerfile, SETUP.md et docs mis à jour ; 3 tests verrouillent la résolution
(découplage, rétro-compat, priorité variable explicite + repli local).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
…annotée

Le README §2 (et docs/manoeuvre/ihm.md §1ter) ne montraient que la vue d'édition
/séquencement. On présente désormais l'IHM via ses **deux vues complémentaires** :

- 1ʳᵉ vue — édition & séquencement (schéma existant, légende rafraîchie : nom de
  sauvegarde pré-formaté + anti-doublon/index ; modale Recharger = base partagée
  cherchable par tension/barres/poste/OC/date + export zip).
- 2ᵉ vue — exploration d'une journée sur la **carte France** : nouveau schéma
  vectoriel annoté `manoeuvre_ihm_explore_map.svg` (même langage visuel que la vue
  d'ensemble), 9 repères : entrée 🗺, fond de carte, disques colorés par tension +
  top-10 VL actifs (halo/rang), connexions inter-postes, sélecteur d'heure, bulle
  d'info (DJ/SA/INT + ⚇), légende filtrante (tout/aucun, double-clic = isoler,
  bascule Lignes), classement, et barre d'exploration Départ/Retenir-cible qui
  bascule vers la 1ʳᵉ vue.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
Remplace les deux schémas SVG stylisés par des **captures réelles annotées** de
l'IHM (repères rouges numérotés, même langage visuel) :

- Figure 1 (`manoeuvre_ihm_overview.png`) — l'éditeur sur le poste **CONCAP3**
  ouvert depuis la carte : barre d'exploration (← Carte / Départ / Retenir cible /
  Niveau), Poste, départ/cible, vue nodale, **Ouvrages isolés (2) exclus du compte
  de nœuds**, sauvegarde (nom pré-formaté + base /data/dgitt), Calculer détaillé,
  séquence animée vérifiée, Recharger. Captions README §2 et ihm.md §2 réécrites.
- Figure 2 (`manoeuvre_ihm_explore_map.png`) — la carte France réelle (4811
  postes · 1774 actifs · 98 % géolocalisés) : Explorer, disques par tension +
  top-10 classés, connexions (Lignes), sélecteur d'heure, légende filtrante,
  classement, recherche poste, contrôles zoom/recentrer/fermer. Captions réécrites.

Ajoute aussi une section README **« Combining actions: the Generalized
Superposition Theorem (GST) »** (entre Action Scoring et Configuration, + entrée
ToC) : EST sur paires topologiques, GST étendant aux actions d'injection
(effacement / curtailment / redispatch) via la convention beta=1.0 qui réutilise
la même reconstruction, AC-anchored ; renvoi à docs/recommender/superposition_module.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1vc3wkuYChuBtLpouaVsa
@marota marota merged commit c72ac27 into main Jun 26, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants