Sanitize les attributs en LECTURE aussi, pas seulement a l'ecriture
Build and deploy / test-python (push) Successful in 11m5s
Build and deploy / test-js (push) Successful in 55s
Build and deploy / lint-python (push) Successful in 6m29s
Build and deploy / lint-js (push) Failing after 1m39s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Failing after 5m18s

Bug reel constate le 21/09/2026 : un element Scenario cree avant la
refonte en arbre de decision (ancien schema plat "situation"/"choices"/
"correct_index") faisait planter silencieusement le panneau Proprietes
cote client des la selection - scenario.nodes etait inexistant sur
l'ancienne forme, aucune erreur visible, juste "il ne se passe rien".
Cause : document_edit.py et document_render.py renvoyaient les
attributs BRUTS de la base au client, jamais revalides - contrairement
a la route d'ecriture qui, elle, sanitize deja avant de persister.

Ajoute document_engine.sanitize_element_attributes(kind, attributes),
point d'entree unique de dispatch kind -> sanitize_X_config, utilise
desormais a la fois en ecriture (document_element_update.py, qui
reutilise ce nouveau dispatch au lieu de son if/elif duplique) ET en
lecture (document_edit.py/document_render.py). Elimine toute la classe
de bug "schema devenu obsolete apres une evolution du modele de
donnees d'un mini-jeu, donnee jamais retouchee depuis" - present et
futur, pas seulement pour Scenario.

Migre les donnees reelles deja affectees (support de test, element 46)
vers le nouveau schema en arbre, en preservant integralement le
contenu deja redige par l'utilisateur (situation + 3 choix/consequences
du scenario "chat sur la route").

Ajoute un test de non-regression qui ecrit delibirement l'ancien schema
en base (en contournant le sanitize de la route d'ecriture, pour
simuler une donnee reellement ancienne jamais nettoyee) puis verifie
que /edit et /render renvoient une structure saine au client.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-09-21 08:07:06 +02:00
co-authored by Claude Sonnet 5
parent a529857379
commit 7e504b7865
7 changed files with 134 additions and 23 deletions
+13 -2
View File
@@ -11,9 +11,20 @@ def document_edit(slug: str) -> str:
support = un projet = un document, voir docs/plan/PLAN.md). Contraste
avec l'environnement 2D (clic sur une carte -> game_dashboard qui liste
ses écrans -> éditeur de scène) : ici la carte "Mes formations" mène
directement ici."""
directement ici.
Les attributs de chaque élément sont revalidés (document_engine.
sanitize_element_attributes) avant d'atteindre le client — jamais les
valeurs brutes stockées telles quelles : un élément dont le schéma a
évolué depuis sa création (ex. le mini-jeu Scénario, passé d'une liste
plate à un arbre de décision) ferait sinon planter silencieusement le
panneau Propriétés côté client, qui suppose la forme ACTUELLE (bug réel
constaté le 21/09/2026)."""
support = db.support_meta(slug)
elements = document_engine.list_document_elements(slug)
elements = [
{**el, "attributes": document_engine.sanitize_element_attributes(el["kind"], el["attributes"])}
for el in document_engine.list_document_elements(slug)
]
return render_template(
"document/document_edit.html",
support=support,
+12 -19
View File
@@ -15,29 +15,22 @@ def document_element_update(slug: str, element_id: int) -> Response | tuple[Resp
systématiquement l'état complet de ses champs.
Quiz, Association, Memory, Mots mêlés et Scénario sont les seuls
kinds revalidés côté serveur (sanitize_quiz_config/
sanitize_association_config/sanitize_memory_config/
sanitize_mots_config/sanitize_scenario_config, même convention que
game_engine/rendering/quiz_box_config.py côté jeu) : leur forme (liste
de questions/choix, liste de paires, liste de cartes, liste de mots,
liste de scénarios) doit rester structurellement correcte pour que le
rendu ne plante jamais, contrairement aux autres kinds
(texte/forme/image...) dont les attributs sont de simples valeurs
scalaires sans structure à garantir."""
kinds revalidés côté serveur (document_engine.sanitize_element_attributes,
même convention que game_engine/rendering/quiz_box_config.py côté
jeu) : leur forme (liste de questions/choix, liste de paires, liste
de cartes, liste de mots, arbre de scénarios) doit rester
structurellement correcte pour que le rendu ne plante jamais,
contrairement aux autres kinds (texte/forme/image...) dont les
attributs sont de simples valeurs scalaires sans structure à
garantir. Même sanitizer utilisé en LECTURE par document_edit.py/
document_render.py — un élément dont les attributs stockés datent
d'un schéma devenu obsolète est ainsi normalisé partout, jamais
seulement à l'écriture."""
element = document_engine.get_document_element(slug, element_id)
if element is None:
return jsonify({"error": "élément introuvable"}), 404
attributes: dict[str, Any] = request.get_json(force=True) or {}
if element["kind"] == "quiz":
attributes = document_engine.sanitize_quiz_config(attributes)
elif element["kind"] == "association":
attributes = document_engine.sanitize_association_config(attributes)
elif element["kind"] == "memory":
attributes = document_engine.sanitize_memory_config(attributes)
elif element["kind"] == "mots":
attributes = document_engine.sanitize_mots_config(attributes)
elif element["kind"] == "scenario":
attributes = document_engine.sanitize_scenario_config(attributes)
attributes = document_engine.sanitize_element_attributes(element["kind"], attributes)
document_engine.update_document_element_attributes(slug, element_id, attributes)
element = db.assert_not_none(
document_engine.get_document_element(slug, element_id),
+10 -2
View File
@@ -11,6 +11,14 @@ def document_render(slug: str) -> Response:
layout côté client après toute mutation structurelle (ajout/déplacement/
suppression) pour reconstruire le canevas depuis la vérité serveur
(recalcul réel des rangées, jamais une simple retouche DOM locale, voir
docs/plan/PLAN.md — "recalcul au déplacement")."""
elements = document_engine.list_document_elements(slug)
docs/plan/PLAN.md — "recalcul au déplacement").
`elements` est revalidé (document_engine.sanitize_element_attributes)
avant d'être renvoyé au client — même raison que routes/document/
document_edit.py : le panneau Propriétés reçoit `data.elements`
directement depuis cette route à chaque rafraîchissement du canevas."""
elements = [
{**el, "attributes": document_engine.sanitize_element_attributes(el["kind"], el["attributes"])}
for el in document_engine.list_document_elements(slug)
]
return jsonify({"html": document_engine.render_document(elements), "elements": elements})