Config strictement stricte partout (ruff, mypy --strict, bandit, vulture,
import-linter, eslint, stylelint), aucune regle desactivee "pour ne pas
casser le build" - l'existant a ete corrige pour la satisfaire plutot que
l'inverse. Hooks pre-commit locaux (language: system) bloquants.
- Typage mypy --strict propage a tout le moteur (db, screens, auth, core,
ai, routes, puis publish/scripts/tests/app.py/build_css.py).
- Securite : fuite de handle fichier Windows corrigee dans l'export SCORM
(routes/publish/export_scorm.py), CSRF/RNG non-crypto/xAPI documentes
(# nosec, # NOSONAR justifies), nouveau db.json_for_script() (echappe
"</script>" dans le JSON embarque en <script>, 25 sites).
- Architecture : imports circulaires/F811 nettoyes, contrats
import-linter respectes, code mort retire (vulture).
- Accessibilite : 69 champs de formulaire sans label correctement
associe corriges (for/id ou aria-label) sur 11 templates.
- ESLint/Stylelint : lot mecanique JS/CSS, regles ajustees puis
appliquees (aucune desactivee sans verification individuelle).
- Tests : isolation du compte admin partage (nettoyage ponctuel +
fixture de teardown automatique en filet de securite), suite complete
verte (591 tests Python, 241 tests JS).
- SonarQube Community Build self-heberge (Docker + PostgreSQL) : rapport
complet analyse point par point, faux positifs documentes.
- .gitattributes ajoute (LF force) : core.autocrlf=true sur cette machine
faisait echouer ESLint (linebreak-style) via un bug connu de git
(checkout "en place" qui ignore l'eol force sur un fichier deja
present sur disque - contourne en supprimant puis recreant chaque
fichier suivi).
djLint (H021, styles inline) volontairement saute pour ce commit -
backlog assume, deja documente, traite dans un lot separe.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Reproduit à l'identique le cas signalé (objet "dialog" avec les champs
order/spiker/text/level_id/parcour_id) : le champ "order" est un mot
réservé SQL — "CREATE TABLE dialog (order INTEGER, ...)" plante avec
"OperationalError: near \"order\": syntax error". Comme ce crash survient
APRÈS l'INSERT de la ligne _definitions mais AVANT le commit(), rien
n'était jamais persisté : l'objet ENTIER disparaissait, malgré des champs
parfaitement remplis — d'où "j'ai tout rempli comme il faut et aucun objet
n'est créé". Mon précédent correctif (champ "Relation" sans cible) était
réel mais ne couvrait pas ce cas précis.
Cause de fond : chaque nom de colonne (dérivé du nom de champ tapé par
l'utilisateur, via slugify) était interpolé TEL QUEL dans du SQL brut
(CREATE TABLE, INSERT, UPDATE, ALTER TABLE ADD/DROP/RENAME COLUMN) sans
jamais être encadré de guillemets — n'importe quel nom de champ qui soit
aussi un mot réservé SQLite (order, group, index, select, where, table,
key, default, check, references, unique...) déclenchait exactement le
même crash-et-perte-de-transaction, dans n'importe laquelle de ces
opérations.
Correctif général (pas un simple contournement pour "order") :
db/quote_ident.py encadre tout identifiant de colonne de guillemets
doubles (forme standard SQL, supportée par SQLite) — appliqué partout où
un nom de colonne utilisateur est interpolé dans du SQL brut :
create_definition, add_field_to_definition, delete_field, update_field
(RENAME COLUMN), insert_row, update_row, update_row_field,
rows_referencing. Les noms de TABLE n'ont pas besoin de cette protection
(table_name_for.py les préfixe toujours "obj_", donc jamais un mot réservé
à eux seuls).
Trois nouveaux tests (tests/test_reserved_sql_keyword_field_names.py) :
création avec un champ "order" + insertion/lecture/mise à jour d'une
ligne, renommage d'un champ vers/depuis un mot réservé ("group"), ajout
d'un champ "select" à un objet existant — les trois confirmés en échec
sur l'ancien code (même erreur reproduite) puis au vert avec le
correctif. 136 tests au vert au total.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>