Contexte cible : Ubuntu 22.04.5 (Jammy), Python 3.10.18, pas de sudo, Poetry, exécution uniquement sur Ubuntu.
Ce document sert de plan d’action exécutable pour les agents (LLM/Codex) chargés de modifier le dépôt Total_Perspective_Vortex.
Tous les agents doivent considérer comme sources de vérité :
- le WBS :
docs/project/wbs_tpv.md - le Gantt / roadmap :
docs/project/gantt_tpv.png,docs/project/roadmap.md - la Murphy Map :
docs/risk/tpv_murphy_map.csv - le GitHub Project :
Total_Perspective_Vortex – WBS & Murphy Map – v1.0 - 2025/11/28 - les issues GitHub du repo :
raveriss/Total_Perspective_Vortex
Aucune implémentation, refactor ou ajout de fichier ne doit être réalisé hors de ce cadrage (WBS + risques + issues).
Un agent n’a jamais le droit de proposer un git commit ou un git push
tant qu’il n’a pas, dans cette réponse précise :
-
Rappelé la checklist pré-commit locale de la section 2).
-
Affiché la section :
CHECKLIST 2) – état AVANT COMMITavec les trois lignes suivantes exactement :
2.2 Pre-commit + static analysis : ✅/❌→ Commit autorisé : ✅/❌
-
Listé les commandes locales à exécuter, dans l’ordre 2.1 → 2.3.
-
Indiqué pour chaque étape si l’état est réellement connu :
- ✅ : l’agent a vu un log de succès ou a lui-même exécuté la commande.
- ❌ : la commande est en échec.
- ❌ (inconnu) : l’agent n’a aucune preuve que la commande est OK.
Règle dure : Si une seule des lignes 2.2, 2.3 est ❌ ou inconnue, l’agent doit écrire explicitement
→ Commit autorisé : ❌.
Dans ce cas, l’agent doit :
- ne pas proposer de commit/push ni de message de commit,
- entrer en boucle de remédiation (fail → fix → re-run) jusqu’à ce que 2.2 + 2.3 soient ✅, ou jusqu’à atteindre une limite d’itérations.
But : un échec de check déclenche une itération de correction. Un agent autonome (ex: Codex) n’a pas le droit de “s’arrêter au fail” si un correctif est possible dans le dépôt.
Règles :
- L’agent exécute la séquence “MODE DEV” (diagnostic rapide) :
poetry run pre-commit run --all-files --show-diff-on-failure
- Si KO :
- il isole le/les hooks en échec,
- il applique un patch minimal,
- il re-run uniquement le/les hooks KO,
- il répète jusqu’au vert.
- Ensuite, avant tout commit, l’agent exécute le “MODE AVANT COMMIT (gate)” :
- 2.2 complet + 2.3 complet (mirroir strict CI)
- Si le gate est vert :
- il peut committer.
- Limite anti-boucle :
- maximum 5 itérations.
- au-delà : l’agent explique la cause racine probable, propose 2 options (ex: ajuster un test flaky, corriger typing, corriger un contrat I/O), et demande les logs manquants si nécessaire.
Interdictions (anti-contournement) :
- pas de
--no-verify - pas de désactivation/suppression de hooks
- pas de “skip” d’un job CI
- pas de modification de seuils (coverage, etc.) pour “faire passer”
Si une étape est KO ou non mentionnée, la réponse doit se terminer par :
« ❌ CI potentiellement en échec : interdiction de committer tant que la checklist 2) n’est pas entièrement verte. »
Toute divergence entre la pipeline locale (section 2) et les jobs CI
(.github/workflows/ci.yml) est considérée comme un échec de l’agent.
Toute réponse qui ne contient pas la section structurée « CHECKLIST 2) – état AVANT COMMIT » est considérée comme invalide.
MODE DEV (boucle itérative) — objectif : garder le dépôt propre pendant l’itération (formatage/lint/types), même si des tests de couverture ou des mutants survivent ailleurs.
-
Autorisé à tout moment :
poetry run pre-commit run --all-files- et/ou les commandes rapides
make lint,make format,make type
-
Obligation de formulation :
- l’agent doit qualifier cela comme un RUN DEV / diagnostic, et ne pas conclure que “tout est bon”.
-
Effet sur le gate :
- un RUN DEV ne change jamais la règle “commit interdit”.
- si 2.3 ne sont pas verts (ou inconnus) :
→ Commit autorisé : ❌reste obligatoire.
-
Comportement attendu :
- si un hook échoue en DEV, l’agent corrige et re-run (boucle) au lieu de s’arrêter sur l’échec.
MODE AVANT COMMIT (gate) — objectif : miroir strict du CI.
-
Obligatoire avant toute suggestion de commit/push :
- exécuter et valider **2.2 + 2.3 (section 2),
- afficher le bloc CHECKLIST 2) – état AVANT COMMIT,
- et n’autoriser le commit que si tout est ✅.
-
Comportement attendu :
- si 2.2 ou 2.3 échoue, l’agent revient en boucle de remédiation (patch → re-run) jusqu’au vert, puis rejoue le gate complet.
- L’agent peut exécuter
poetry run pre-commit run --all-filesen MODE DEV, même si 2.3 (make cov) ne sont pas encore verts. - Après un RUN DEV, l’agent doit :
- indiquer explicitement “MODE DEV / diagnostic”,
- rapporter le résultat de
pre-commit(OK/KO), - proposer un patch minimal si un hook échoue,
- et rappeler que le gate AVANT COMMIT reste inchangé.
- Interdictions strictes :
- présenter un RUN DEV comme une validation “AVANT COMMIT”,
- suggérer un commit/push tant que la checklist 2) n’est pas entièrement ✅.
Les contraintes suivantes doivent figurer simultanément dans README, AGENTS et Murphy Map et être respectées dans le code :
- Finalité : classer en temps « réel » un signal EEG (imagination de mouvement A ou B).
- Source des données : jeu Physionet EEG motor imagery obligatoire ; signaux structurés en matrice channels × time avec runs découpés et labellisés proprement.
- Prétraitement obligatoire : visualisation du brut (script dédié), filtrage des bandes utiles (theta/alpha/beta…), visualisation après prétraitement, extraction des features (spectre/PSD…), et interdiction implicite d’utiliser
mne-realtime. - Pipeline ML : utilisation de
sklearn.pipeline.Pipeline, transformer maison héritant deBaseEstimatoretTransformerMixin, réduction de dimension PCA/ICA/CSP/CSSP implémentée à la main (NumPy/SciPy autorisés, pas de version prête de sklearn/MNE). - Entraînement/validation/test :
cross_val_scoresur le pipeline complet, splits Train/Validation/Test distincts (pas d’overfit), accuracy moyenne ≥ 75 % sur tous les sujets de test et les 6 runs sur données jamais apprises. - Temps réel : le script
predictlit un flux simulé (lecture progressive) et fournit chaque prédiction en moins de 2 secondes après réception d’un chunk. - Architecture : présence d’un script train et d’un script predict ; le dépôt final versionné contient uniquement le code Python (dataset exclu).
- Bonus facultatifs : wavelets pour le spectre, classifieur maison, autres datasets EEG.
- Formalisme mathématique : pour le transformer, avec X ∈ R^{d × N}, produire une matrice W telle que W^T X = X_{CSP}/X_{PCA}/X_{ICA}.
- Posture défense-proof globale : pour implémenter
Total_Perspective_Vortexavec une posture TDD systématique, couverture 90 %, diff=190 %, contrôle par fichier, CI Ubuntu-only.
Avant de générer du code, tout agent doit :
-
Identifier le WBS ID concerné
- Chercher dans
docs/project/wbs_tpv.mdla tâche correspondante. - Si aucune tâche ne correspond, ne pas inventer de feature : proposer d’abord une mise à jour du WBS.
- Chercher dans
-
Consulter la Murphy Map
- Filtrer
docs/risk/tpv_murphy_map.csvsur ce WBS ID. - Lister les
Murphy IDassociés et leurs risques (cause, effet). - Adapter le design / les tests pour couvrir ces risques.
- Filtrer
-
Travailler via une issue GitHub
- Vérifier qu’une issue existe pour ce WBS ID.
- Si ce n’est pas le cas, proposer une issue à créer avec :
- titre = WBS ID + résumé court,
- lien vers les sections WBS + Murphy Map concernées.
-
Mettre à jour l’item dans le GitHub Project
- Associer l’issue à l’item du Project.
- Mettre à jour les champs :
Status,Phase,Type,Priority,Risk scoresi pertinent.
-
Ne jamais livrer de code sans trace WBS
- Tout nouveau module / script / test doit pouvoir être relié à un
WBS IDet, si applicable, à un ou plusieursMurphy ID. - En cas de doute, l’agent doit refuser l’implémentation et demander une clarification WBS / risques.
- Tout nouveau module / script / test doit pouvoir être relié à un
-
Respect strict de la structure TPV
- Aucun fichier ne doit être créé en dehors de :
src/tpv/(code ML / EEG)scripts/(scripts CLI ou visualisation)tests/(tests)docs/(documentation)
- Aucun fichier Python ne doit être ajouté à la racine, sauf
mybci.py. - Toute proposition de nouveau fichier doit pointer vers :
- un WBS ID,
- une issue GitHub existante ou à créer,
- un ou plusieurs Murphy ID associés.
- Aucun fichier ne doit être créé en dehors de :
- Init repo +
README.md(usage, séquence de soutenance, badges CI si voulu) -
LICENSE(MIT) +author - Convention commits :
feat:,fix:,refactor:,test:,docs:
- Installer Poetry (utilisateur) :
curl -sSL https://install.python-poetry.org | python3 - export PATH="$HOME/.local/bin:$PATH" poetry config virtualenvs.in-project true poetry env use 3.10
-
pyproject.toml— versions Python verrouillées :[tool.poetry] name = "total-perspective-vortex" version = "0.1.0" description = "EEG Brain-Computer Interface pipeline for the Total Perspective Vortex project." authors = ["raveriss <you@example.com>"] license = "MIT" readme = "README.md" packages = [{ include = "tpv", from = "src" }] [tool.poetry.dependencies] python = ">=3.10,<3.11" numpy = "^1.26" pandas = "^2.2" scipy = "^1.11" scikit-learn = "^1.3" mne = "^1.6" matplotlib = "^3.8" joblib = "^1.4" [tool.poetry.group.dev.dependencies] pytest = "^8.3" pytest-cov = "^5.0" pytest-timeout = "^2.3" pytest-randomly = "^3.15" hypothesis = "^6.112" mypy = "^1.11" ruff = "^0.6" black = "^24.10" isort = "^5.13" bandit = "^1.7" mutmut = "^3.0" radon = "^6.0" xenon = "^0.9" pre-commit = "^4.0" pip-audit = "^2.7" coverage = "^7.6" [tool.black] line-length = 88 target-version = ["py310"] [tool.isort] profile = "black" line_length = 88 known_first_party = ["mybci", "tpv"] src_paths = ["src", "scripts", "tests"] [tool.ruff] line-length = 88 target-version = "py310" [tool.ruff.lint] select = ["E", "F", "W", "I", "B", "PL", "C4"] ignore = [] [tool.ruff.lint.isort] known-first-party = ["mybci", "tpv"] [tool.mutmut] paths_to_mutate = ["mybci.py", "src/tpv"] tests_dir = "tests" pytest_add_cli_args = ["-q"] mutate_only_covered_lines = true [tool.pytest.ini_options] pythonpath = ["src", ".", ".."] [tool.mypy] python_version = "3.10" check_untyped_defs = true warn_unused_ignores = true warn_return_any = true warn_redundant_casts = true strict_optional = true no_implicit_optional = true show_error_codes = true pretty = true ignore_missing_imports = true files = "src scripts tests" [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api"
# ========================================================================================
# Makefile - Automatisation pour le projet Total_Perspective_Vortex
# Objectifs :
# - Simplifier l’installation et la gestion de l’environnement (Poetry / venv)
# - Automatiser les vérifications (lint, format, type-check, tests, coverage, mutation)
# - Fournir des commandes pratiques pour l’entraînement et la prédiction du modèle
# ========================================================================================
.PHONY: install lint format type test cov mut train predict activate deactivate
VENV = .venv
VENV_BIN = $(VENV)/bin/activate
# --- Benchmarks ---------------------------------------------------------------
BENCH_DIR := data/benchmarks
BENCH_CSVS := $(wildcard $(BENCH_DIR)/*.csv)
# Utilisation raccourcie de Poetry
POETRY = poetry run
# ----------------------------------------------------------------------------------------
# Installation des dépendances (dev inclus)
# ----------------------------------------------------------------------------------------
install:
poetry install --with dev
# ----------------------------------------------------------------------------------------
# Vérifications de qualité du code
# ----------------------------------------------------------------------------------------
# Linting avec Ruff (analyse statique rapide)
lint:
$(POETRY) ruff check .
# Formatage + correction auto avec Ruff
format:
$(POETRY) ruff format . && $(POETRY) ruff check --fix .
# Vérification des types avec Mypy
type:
$(POETRY) mypy src scripts tests
# ----------------------------------------------------------------------------------------
# Tests et couverture
# ----------------------------------------------------------------------------------------
# Exécution des tests unitaires
test:
$(POETRY) pytest -vv
# Analyse de la couverture avec rapport JSON, HTML et console (90% requis)
cov:
$(POETRY) coverage run -m pytest && \
$(POETRY) coverage json -o coverage.json && \
$(POETRY) coverage xml -o coverage.xml && \
$(POETRY) coverage html --skip-empty --show-contexts && \
$(POETRY) coverage report --fail-under=90
# ----------------------------------------------------------------------------------------
# Commandes liées au modèle (Poetry)
# ----------------------------------------------------------------------------------------
TRAIN_SUBJECT ?= S001
TRAIN_RUN ?= R01
PREDICT_SUBJECT ?= $(TRAIN_SUBJECT)
PREDICT_RUN ?= $(TRAIN_RUN)
# Entraînement du modèle : exemple minimal avec sujet et run de démonstration
train:
$(POETRY) python mybci.py $(TRAIN_SUBJECT) $(TRAIN_RUN) train
# Prédiction : exemple minimal réutilisant les identifiants ci-dessus
predict:
$(POETRY) python mybci.py $(PREDICT_SUBJECT) $(PREDICT_RUN) predict
# Affiche la commande pour activer le venv
activate:
@echo "Chemin de l'environnement Poetry :"
@poetry env info -p
@echo
@echo "Pour activer manuellement cet environnement :"
@echo " source $$(poetry env info -p)/bin/activate"
# Affiche la commande pour désactiver le venv
deactivate:
@echo "Pour quitter l'environnement :"
@echo " deactivate"
# ----------------------------------------------------------------------------------------
# Règle générique pour ignorer les cibles numériques (ex. make predict-nocheck 23000)
# ----------------------------------------------------------------------------------------
%:
@:.github/workflows/ci.yml
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [ main, develop ]
tags: [ 'v*' ]
paths-ignore:
- '**/*.md'
- '**/*.txt'
- '**/*.png'
pull_request:
branches: [ main, develop ]
paths-ignore:
- '**/*.md'
- '**/*.txt'
- '**/*.png'
env:
# Version Python canonique utilisée par la CI (alignée avec pyproject.toml)
PYTHON_VERSION: "3.10"
jobs:
pre-commit:
name: Pre-commit checks
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y libasound2-dev
- name: Install Poetry (retry)
run: |
python -m pip install --user --upgrade pip
for attempt in 1 2 3; do
python -m pip install --user --retries 3 --timeout 60 poetry==1.8.4 && break
if [ "$attempt" -eq 3 ]; then
echo "Poetry installation failed after ${attempt} attempts." >&2
exit 1
fi
echo "Retrying Poetry installation (attempt ${attempt}/3)..." >&2
sleep 5
done
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
poetry config virtualenvs.create true
poetry config virtualenvs.in-project true
- name: Cache virtualenv
id: cache-poetry
uses: actions/cache@v3
with:
path: .venv
key: venv-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ hashFiles('**/poetry.lock') }}
- name: Install dependencies (cache miss)
if: steps.cache-poetry.outputs.cache-hit != 'true'
run: poetry install --no-interaction --with dev --no-root
- name: Install project in editable mode
run: poetry install --no-interaction --with dev
- name: Run pre-commit
run: poetry run pre-commit run --all-files
static-analysis:
name: Static Analysis
runs-on: ubuntu-22.04
needs: pre-commit
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- run: sudo apt-get update && sudo apt-get install -y libasound2-dev
- name: Install Poetry (retry)
run: |
python -m pip install --user --upgrade pip
for attempt in 1 2 3; do
python -m pip install --user --retries 3 --timeout 60 poetry==1.8.4 && break
if [ "$attempt" -eq 3 ]; then
echo "Poetry installation failed after ${attempt} attempts." >&2
exit 1
fi
echo "Retrying Poetry installation (attempt ${attempt}/3)..." >&2
sleep 5
done
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
poetry config virtualenvs.create true
poetry config virtualenvs.in-project true
- uses: actions/cache@v3
id: cache-poetry
with:
path: .venv
key: venv-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ hashFiles('**/poetry.lock') }}
- name: Install dependencies (cache miss)
if: steps.cache-poetry.outputs.cache-hit != 'true'
run: poetry install --no-interaction --with dev --no-root
- name: Install project
run: poetry install --no-interaction --with dev
- name: Run Black check
run: poetry run black --check .
- name: Run isort check
run: poetry run isort --check-only .
- name: Run Ruff
run: poetry run ruff check .
- name: Run MyPy
run: poetry run mypy src scripts tests
- name: Audit dependencies with pip-audit
run: poetry run pip-audit --progress-spinner=off
tests:
runs-on: ubuntu-22.04
needs: static-analysis
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install Poetry (retry)
run: |
python -m pip install --user --upgrade pip
for attempt in 1 2 3; do
python -m pip install --user --retries 3 --timeout 60 poetry==1.8.4 && break
if [ "$attempt" -eq 3 ]; then
echo "Poetry installation failed after ${attempt} attempts." >&2
exit 1
fi
echo "Retrying Poetry installation (attempt ${attempt}/3)..." >&2
sleep 5
done
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
poetry config virtualenvs.create true
poetry config virtualenvs.in-project true
- name: Cache virtualenv
id: cache-poetry
uses: actions/cache@v3
with:
path: .venv
key: venv-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ hashFiles('**/poetry.lock') }}
- name: Install dependencies (with dev)
if: steps.cache-poetry.outputs.cache-hit != 'true'
run: poetry install --no-interaction --with dev
- name: Ensure project installed
if: steps.cache-poetry.outputs.cache-hit == 'true'
run: poetry install --no-interaction --with dev
- name: Run tests with coverage (Makefile)
run: make cov
- name: Generate coverage.xml for Codecov
run: poetry run coverage xml -o coverage.xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
files: ./coverage.xml
disable_search: true
flags: unittests
name: ci-ubuntu-py${{ env.PYTHON_VERSION }}
slug: raveriss/Total_Perspective_Vortex
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
build:
name: Build Package
runs-on: ubuntu-22.04
needs: [static-analysis, tests]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- run: sudo apt-get update && sudo apt-get install -y libasound2-dev
- name: Install Poetry (retry)
run: |
python -m pip install --user --upgrade pip
for attempt in 1 2 3; do
python -m pip install --user --retries 3 --timeout 60 poetry==1.8.4 && break
if [ "$attempt" -eq 3 ]; then
echo "Poetry installation failed after ${attempt} attempts." >&2
exit 1
fi
echo "Retrying Poetry installation (attempt ${attempt}/3)..." >&2
sleep 5
done
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
poetry config virtualenvs.create true
poetry config virtualenvs.in-project true
- run: poetry install --no-interaction --no-root
- name: Build package
run: poetry build
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/Exemple minimal de CI ci-dessous. La configuration réelle utilisée est définie dans
.github/workflows/ci.yml(jobs pré-commit, static-analysis, tests, build).
- Definition of Ready : pas de code sans au moins un test qui échoue.
- Definition of Done : tests verts, CLI/doc à jour.
- Hooks (local) :
pre-commit:ruff format --check,ruff check,mypy(rapide)
-
src/tpv/classifier.py: -
src/tpv/dimensionality.py: -
src/tpv/features.py: -
src/tpv/__init__.py: -
src/tpv/pipeline.py: -
src/tpv/predict.py: -
src/tpv/preprocessing.py: -
src/tpv/realtime.py: -
src/tpv/train.py: -
src/tpv/utils.py: -
tests/: unitaires + E2E + erreurs I/O + contrats. -
Bonus isolé :
Main guard requis partout : if __name__ == "__main__": main()
et exécution modulaire via python -m tpv.train / python -m tpv.predict
ou via le point d'entrée python mybci.py <subject> <run> {train,predict}.
Avant tout git commit ou proposition de commit message, l’agent doit :
- Énoncer cette checklist dans sa réponse.
- Proposer les commandes à exécuter dans cet ordre exact (2.1).
- Demander explicitement les résultats (logs) si l’agent ne peut pas exécuter lui-même les commandes.
- Refuser le commit si une étape n’est pas verte ou inconnue.
Ajout : si une étape est KO, l’agent ne se contente pas de refuser le commit : il propose/applique un patch minimal puis demande ou exécute le re-run jusqu’au vert (boucle de remédiation). Cette section est le miroir local des jobs CI :
pre-commit(incluantcheck yaml/toml,fix end of files,trim trailing whitespace,mixed line ending,black,isort,ruff,mypy,bandit,radon,xenon, etc.),static-analysis,tests(couverture viamake cov).
L’agent doit toujours rappeler en texte clair que :
« Tant que 2.2, 2.3 ne sont pas toutes ✅, le commit est interdit. »
Si l’agent ne sait pas si l’environnement est à jour (nouveau clone, changement de branche, doute sur poetry.lock), il doit exécuter systématiquement 2.1.1 et 2.1.2.
poetry install --no-interaction --with dev- Vérifier que la commande
poetry run pytest -qfonctionne au moins une fois.
L’agent doit proposer cette séquence exacte et dans cet ordre :
poetry run pre-commit run --all-files
poetry run black --check .
poetry run isort --check-only .
poetry run ruff check .
poetry run mypy src scripts tests
poetry run pip-audit --progress-spinner=offRègles :
-
Si
pre-commitéchoue (check yaml,check toml,fix end of files,trim trailing whitespace,mixed line ending,black,isort,ruff,mypy, etc.) :-
l’agent doit :
- expliquer brièvement l’erreur,
- appliquer/proposer un patch minimal,
- re-run d’abord le(s) hook(s) KO,
- puis re-run toute la séquence 2.2 pour valider le retour au vert.
-
si l’agent a la capacité d’exécuter (ex: Codex), il doit re-run lui-même et inclure les logs. Sinon, il demande les logs au user.
-
-
Tant qu’une commande de 2.2 est KO ou non exécutée :
- l’agent ne doit pas proposer de message de commit,
- l’agent ne doit pas indiquer que « tout est bon »,
- l’agent ne doit pas parler de
git push.
L’agent doit proposer :
make covmake cov doit :
- générer
coverage.json,coverage.xml,htmlcov/, - se terminer avec
coverage report --fail-under=90OK.
Si make cov est KO, la réponse doit :
- pointer les fichiers sous-couverts,
- proposer au moins un test supplémentaire pour remonter la couverture,
- rappeler de relancer
make covjusqu’à obtention de 90 %.
Ajout (boucle) :
- l’agent doit itérer : corriger → re-run
make covjusqu’au vert, ou s’arrêter après 5 itérations avec diagnostic + options.
Un commit n’est valide que si toutes les conditions suivantes sont satisfaites :
- 2.2 complète et verte.
La réponse de l’agent doit toujours contenir, avant toute suggestion de message de commit, une synthèse explicite :
« Checklist 2) :
- 2.2 Pre-commit + static analysis : ✅/❌ → Commit autorisé : ✅/❌. »
Si l’agent ne peut pas remplir cette synthèse de façon honnête, il doit conclure par :
« ❌ CI potentiellement en échec : commit interdit tant que la checklist 2) n’est pas entièrement verte. »
Objectifs : couverture >= <...>%
(coverage report --fail-under=<...>), exécution déterministe, temps CI <= <...>, zéro crash sur cas nominaux et erreurs attendues, traçabilité complète vers WBS, risques et exigences projet.
Traçabilité : WBS <WBS_IDs>, risques <RISK_IDs>, issues <ISSUE_refs>, jeux de données <DATASET_refs>, artefacts <ARTIFACT_refs>, exigences <SPEC_refs>.
- Couvrir tous les composants critiques :
<src/...>,<scripts/...>,<entrypoints>,<core_modules>. - Vérifier les invariants :
shapes
<...>, dtypes<...>, plages<...>, absence deNaN/Inf, non-mutation des entrées. - Vérifier les cas limites : entrées vides, tailles minimales, valeurs extrêmes, colonnes absentes, types invalides, doublons, divisions nulles, labels inconnus, formats incohérents.
- Vérifier les erreurs attendues :
messages
<ERROR_format>, exceptions<...>, codes de retour<...>. - Vérifier les contrats API :
signatures stables, paramètres par défaut, compatibilité ascendante
<...>, sérialisation/rechargement stables. - Vérifier la reproductibilité locale : seed fixée, sorties stables, absence d’aléatoire non contrôlé.
- Tester les schémas d’entrée :
colonnes/features obligatoires
<...>, types<...>, plages<...>, cardinalités<...>. - Tester les données dégradées : fichiers manquants, lignes corrompues, valeurs hors bornes, encodage invalide, timestamps incohérents, valeurs manquantes.
- Vérifier la cohérence métier :
mapping labels/targets
<...>, classes attendues<...>, règles métier bloquantes<...>. - Vérifier la prévention des fuites de données :
split strict
<group_key/time_key/sujet/session/...>. - Vérifier les règles de nettoyage : aucune suppression silencieuse, comptage avant/après, traçabilité des éléments rejetés.
- Tester le pipeline complet :
load -> validate -> preprocess -> features -> model -> postprocess. - Vérifier que
train/fitetpredict/inferpartagent exactement la même config<config_source>. - Vérifier la cohérence train/predict : mêmes colonnes, même ordre, mêmes transformations, même normalisation/encodage, mêmes mappings.
- Vérifier
save -> load -> predictsans dérive sur données identiques. - Vérifier la compatibilité des composants custom avec
<framework_ml/interface_contract>. - Ajouter un test de non-régression sur
<metric_principale>avec données jamais vues.
- Définir les métriques :
<metric_1>,<metric_2>,<metric_calibration>,<...>. - Définir les seuils d’acceptation :
<metric_1> >= <...>,<metric_2> <= <...>. - Exécuter la stratégie d’évaluation :
<cv_strategy / holdout / temporal split / grouped split / ...>. - Vérifier la robustesse inter-splits/inter-domaines :
<subject/run/site/time_period/domain/...>. - Vérifier la stabilité statistique : variance des scores bornée, pas d’effondrement sur un fold isolé, cohérence des résultats entre runs.
- Tester le flux nominal :
<command_train>puis<command_predict>puis<command_eval>. - Tester les modes dégradés : artefact absent, permissions insuffisantes, dépendance manquante, dataset introuvable, config invalide, environnement incomplet.
- Vérifier les sorties :
formats
<csv/json/parquet/pkl/joblib/...>, encodage UTF-8, schéma stable, contenu minimal attendu. - Vérifier les entrypoints associés :
make <...>,poetry run <...>,<runner_cmd>. - Vérifier l’absence de dépendance à des chemins absolus locaux ou à un état machine implicite.
- Vérifier que les logs restent lisibles, structurés, utiles au debug, sans polluer les sorties contractuelles.
- Mesurer et borner :
temps d’entraînement
<= <...>, latence moyenne<= <...>, latence max<= <...>, mémoire max<= <...>, throughput>= <...>, taille artefact<= <...>. - Vérifier la stabilité du premier appel (
warm-up) vs appels suivants. - Vérifier la tenue à l’échelle :
<N lignes>,<N features>,<N classes>,<N fichiers>,<N batches>. - Vérifier l’absence de régression de performance entre versions critiques.
- Vérifier que toute optimisation n’introduit ni fuite de données, ni approximation métier invalide, ni comportement non déterministe.
- Fixer et tester les seeds globales :
<numpy>,<framework_ml>,<python_random>,<...>. - Versionner datasets, configs et artefacts :
<data_versioning_strategy>. - Vérifier la reproductibilité inter-machines :
écart métrique toléré
<= <...>. - Enregistrer le fingerprint d’exécution : commit, config hash, dataset hash, environnement, seed, date, métriques finales.
- Vérifier la sûreté des écritures : création de dossier si nécessaire, refus propre si permissions insuffisantes, pas d’écrasement silencieux non prévu.
- Scanner dépendances et vulnérabilités :
<tool_security_scan>. - Vérifier les contraintes de conformité ou de confidentialité si applicables :
<PII/GDPR/...>.
- Exécuter systématiquement :
<lint_cmd>,<format_cmd>,<typecheck_cmd>,<test_cmd>,<coverage_cmd>,<benchmark_cmd>,<audit_cmd>. - Bloquer le merge si un seuil échoue : couverture, métriques, performance, sécurité, reproductibilité, conformité I/O.
- Exiger les preuves de validation :
rapports
<coverage>,<benchmark>,<eval_report>,<risk_report>,<artifact_manifest>. - Déclarer explicitement le statut final :
Release autorisée : ✅/❌.
- Aucun crash sur cas nominal, erreurs utilisateur attendues et données invalides.
- Toutes les sorties contractuelles sont produites au bon format avec le bon schéma et le bon contenu minimal.
- La métrique principale
<metric_principale>atteint au minimum<...>. - Les contraintes de performance
<...>sont respectées. - Les tests sont automatisables en local et en CI.
- Les preuves restent traçables vers WBS, risques, exigences, datasets et artefacts.
- Les formules utilisées pour CSP/PCA/ICA doivent être documentées (docstring + référence mathématique).
python mybci.py S001 R01 train
python mybci.py S001 R01 predictPour améliorer le diagnostic, la lisibilité des exécutions CLI et la
maintenabilité du projet, l’agent peut créer et utiliser une classe
partagée AnalysisLogger dédiée à la journalisation console d’analyse.
AnalysisLogger sert exclusivement à produire des logs de diagnostic
structurés, lisibles et visuellement homogènes pendant l’exécution
du programme.
Cette classe doit aider à :
- suivre les grandes étapes d’exécution ;
- faciliter le debug local ;
- rendre les logs plus lisibles grâce à des séparateurs stables ;
- localiser rapidement une phase fautive ;
- améliorer la compréhension du flux d’exécution.
-
Implémentation centralisée
- La logique de journalisation d’analyse doit être regroupée dans
une classe dédiée
AnalysisLogger. - L’agent doit éviter de dupliquer une logique de log similaire dans plusieurs fichiers, sauf nécessité réelle clairement justifiée.
- La logique de journalisation d’analyse doit être regroupée dans
une classe dédiée
-
Activation optionnelle
- La journalisation d’analyse doit être désactivée par défaut.
- Elle doit pouvoir être activée explicitement via un argument CLI, un flag, une option de configuration ou un mécanisme équivalent.
- Son activation ne doit jamais modifier le comportement métier, uniquement la verbosité et la lisibilité des sorties console.
-
Séparation stricte des responsabilités
AnalysisLoggerne doit contenir aucune logique métier.- Il ne doit ni transformer les données, ni piloter le flux métier, ni changer le résultat fonctionnel du programme.
- Son rôle est limité à l’affichage de diagnostics.
-
Injection explicite
- Le logger doit être instancié au niveau du point d’entrée principal, puis transmis explicitement aux composants qui en ont besoin.
- L’agent doit éviter les variables globales cachées pour piloter les logs.
-
Aucun
print()d’analyse dispersé- Les affichages d’analyse ne doivent pas être éparpillés directement dans le code métier.
- Hors messages utilisateur strictement nécessaires, les logs
d’analyse doivent passer par
AnalysisLogger.
-
Style visuel stable
- La classe doit fournir un style d’affichage constant : séparateurs, titres, sous-sections, synthèses de valeurs.
- Les sorties doivent rester sobres, lisibles et homogènes d’une exécution à l’autre.
-
Contenu attendu des logs
- Les logs peuvent afficher, selon le contexte :
- nom de phase ;
- chemin de fichier ;
- paramètres d’entrée ;
- dimensions, shapes ou tailles ;
- statistiques synthétiques ;
- état d’avancement ;
- résultats intermédiaires utiles ;
- temps d’exécution ;
- informations de sauvegarde / chargement.
- Les logs doivent éviter les sorties trop volumineuses ou bruitées, sauf besoin ponctuel clairement justifié.
- Les logs peuvent afficher, selon le contexte :
-
Nommage explicite des méthodes
- Les méthodes doivent décrire précisément leur rôle.
- Exemples :
log_headerlog_section_headerlog_input_summarylog_configuration_summarylog_processing_steplog_output_summarylog_save_summarylog_warning_summary
- Éviter les noms trop vagues comme
log_data,log_info,log_steps’ils ne sont pas suffisamment précis.
-
Robustesse
- Si le logger est désactivé, ses méthodes doivent retourner immédiatement sans produire d’effet parasite.
- Le logger ne doit jamais faire échouer le programme pour un simple besoin de diagnostic console.
-
Testabilité
- Le comportement du logger doit être testable.
- Les tests doivent vérifier au minimum :
- qu’aucune sortie n’est produite lorsqu’il est désactivé ;
- que les en-têtes et séparateurs attendus apparaissent quand il est activé ;
- qu’il n’altère jamais le résultat fonctionnel du programme.
-
Compatibilité avec les sorties attendues
- La journalisation d’analyse ne doit pas casser un format de sortie attendu par des tests, un évaluateur ou un consommateur machine.
- Si une sortie standard doit rester strictement contrôlée, les logs d’analyse doivent être désactivés par défaut ou redirigés selon le contrat du projet.
-
Extensibilité
- La classe doit être conçue pour accueillir de nouvelles méthodes de log sans casser le code existant.
- Toute nouvelle phase importante du programme doit pouvoir recevoir une méthode de log dédiée, explicite et cohérente avec le style existant.
Cette trame constitue un noyau minimal. L’agent peut ensuite ajouter des méthodes spécialisées selon les besoins du projet.
class AnalysisLogger:
"""Logger verbeux dédié au diagnostic d’exécution."""
GRAPHICAL_SEPARATOR = "/* -'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-',-' */"
VALUE_SEPARATOR = "--------------------------------------------------------------"
def __init__(self, enabled: bool = False) -> None:
self.enabled = enabled
def _log_graphical_separator(self) -> None:
if not self.enabled:
return
print(f"\n{self.GRAPHICAL_SEPARATOR}")
def log_header(self, title: str) -> None:
if not self.enabled:
return
print("")
self._log_graphical_separator()
print(f"/* {title.center(68)} */")
self._log_graphical_separator()
def log_key_value(self, label: str, value: object) -> None:
if not self.enabled:
return
print(f"{label}: {value}")Exemple d'appel dans le code source :
# Pour accepter l'execution depuis le dossier scripts directement.
from scripts.analysis_logger import AnalysisLogger
# Pour afficher l'etat initial des donnees si le mode analyse est actif.
analysis_logger.log_key_value("students_count", students_count)- Sauvegardes de modèles et paramètres dans un répertoire dédié (
models/ou équivalent), jamais danssrc/. - Ne jamais committer les datasets bruts ou fichiers issus de Physionet.
.
├── AGENTS.md
├── author
├── codecov.yml
├── create_tpv_fields.sh
├── docs
│ ├── assets
│ │ ├── image01.png
│ │ └── image02.png
│ ├── project
│ │ ├── gantt_tpv.png
│ │ ├── roadmap.md
│ │ └── wbs_tpv.md
│ ├── risk
│ │ └── tpv_murphy_map.csv
│ ├── total_perspective_vortex.en.checklist.pdf
│ └── Total_Perspective_Vortex.en.subject.pdf
├── LICENSE
├── Makefile
├── mybci.py
├── poetry.lock
├── poetry.toml
├── pyproject.toml
├── README.md
├── scripts
│ ├── import_murphy_issues.py
│ ├── import_murphy_to_project.py
│ ├── predict.py
│ ├── train.py
│ └── visualize_raw_filtered.py
├── src
│ └── tpv
│ ├── classifier.py
│ ├── dimensionality.py
│ ├── features.py
│ ├── __init__.py
│ ├── pipeline.py
│ ├── predict.py
│ ├── preprocessing.py
│ ├── realtime.py
│ ├── train.py
│ └── utils.py
└── tests
├── test_classifier.py
├── test_dimensionality.py
├── test_mybci.py
├── test_pipeline.py
├── test_preprocessing.py
└── test_realtime.py
À maintenir synchronisé avec
docs/risk/tpv_murphy_map.csv. Chaque WBS ID modifié doit rappeler au moins un Murphy ID couvert par les tests.
pytest -q→ tout vertcoverage run -m pytest && coverage json && coverage report --fail-under=90(branches)- Contrôle par fichier : script CI sur
coverage.json3bis. Upload vers Codecov (coverage.xml) - Mutation testing (scope global mandatory) ≥ 90 % + aucun survivant sur les zones critiques.
- Démo E2E :
predict(0)=0→train→predict≈csv(MAJ simultanée validée) - Vérif visuelle
htmlcov/(tout vert) - README : commande
predict→train→predict, aucune mention de lib “magique” - Vérif environnement : exécution validée uniquement sous Ubuntu 22.04 (soutenance école 42)
usage: train.py
usage: predict.py
- `ERROR:
- `ERROR:
- `ERROR:
vulture,bandit,radon/xenon(analyse dead‑code/sécurité/complexité)- Job Python 3.11 Ubuntu (smoke) en plus du 3.10
Toute réponse qui propose du code ou un changement de fichier doit impérativement respecter ce format, dans cet ordre :
-
Contexte / WBS / Murphy
- WBS ID concerné.
- Murphy ID concernés.
- Issue GitHub associée (lien ou titre).
-
Plan
- Liste des étapes de modification du code.
- Impact attendu sur les risques (Murphy) et sur la BCI (section 🎯).
-
Checklist pré-commit (section 2)
-
Rappel des étapes 2.1.
-
Commandes à exécuter dans l’ordre.
-
Bloc obligatoire :
CHECKLIST 2) – état AVANT COMMIT 2.2 Pre-commit + static analysis : ✅/❌ → Commit autorisé : ✅/❌ -
L’agent doit expliquer pourquoi il met ✅ ou ❌ (logs vus, échec, inconnu).
-
Si ❌ :
- l’agent doit inclure un sous-bloc “BOUCLE DE REMÉDIATION” :
- LOG du fail
- patch minimal
- commandes de re-run (hook KO puis gate complet)
- itération N (max 5)
- l’agent doit inclure un sous-bloc “BOUCLE DE REMÉDIATION” :
-
-
Patch proposé
- Diff formaté (un seul patch cohérent).
- Références claires aux tests impactés ou ajoutés.
-
Validation
-
Synthèse explicite (en cohérence avec le bloc CHECKLIST 2) ) :
- 2.2 : ✅/❌
- 2.3 : ✅/❌
-
Interdiction d’écrire ou suggérer une commande
git commitougit pushsi→ Commit autorisén’est pas à ✅. -
Si une case est ❌ ou inconnue, la réponse doit se terminer par :
« ❌ CI potentiellement en échec : commit interdit tant que la checklist 2) n’est pas entièrement verte. »
-
Le pattern doit ressembler à :
- RUN DEV :
pre-commitKO → log inclus - Patch minimal
- Re-run hook KO → OK
- RUN AVANT COMMIT : 2.2 + 2.3 → OK
- Bloc CHECKLIST 2) : ✅ → Commit autorisé ✅ → commit
Toute réponse qui ne suit pas ce format doit être considérée comme non conforme au blueprint AGENTS.
Cas : correction mineure dans
src/tpv/utils.pypour clarifier un message d’erreur, WBS ID = TPV-UTIL-01.
- Contexte / WBS / Murphy
- WBS ID : TPV-UTIL-01 (utilitaires communs BCI)
- Murphy ID : M-UTIL-01 (messages d’erreurs ambigus)
- Issue GitHub :
TPV-UTIL-01 – Clarifier message d'erreur invalid channel
- Plan
- Mettre à jour le message d’erreur dans
utils.pypour mentionner explicitement l’ID de canal. - Ajouter/adapter un test dans
tests/test_utils.pyqui vérifie le message. - Rejouer la pipeline locale 2.2.
- Checklist pré-commit (section 2)
Commandes à exécuter :
# 2.1 Préparation (si besoin)
poetry install --no-interaction --with dev
poetry run pytest -q
# 2.2 Pre-commit + static analysis
poetry run pre-commit run --all-files
poetry run black --check .
poetry run isort --check-only .
poetry run ruff check .
poetry run mypy src scripts tests
poetry run pip-audit --progress-spinner=off
# 2.3 Tests + couverture 90 %
make cov
Supposons que toutes ces commandes ont été exécutées avec succès (logs OK).
```text
CHECKLIST 2) – état AVANT COMMIT
2.2 Pre-commit + static analysis : ✅
→ Commit autorisé : ✅- Patch proposé
diff --git a/src/tpv/utils.py b/src/tpv/utils.py
index 1234567..89abcde 100644
--- a/src/tpv/utils.py
+++ b/src/tpv/utils.py
@@ -10,7 +10,8 @@ def validate_channel_index(index: int, max_index: int) -> None:
- # Vérifie que l'index de canal est dans les bornes autorisées
+ # Refuse explicitement les canaux hors bornes pour faciliter le debug
if index < 0 or index > max_index:
- raise ValueError("Invalid channel index")
+ raise ValueError(
+ f"Index de canal invalide: {index} (max autorisé: {max_index})"
+ )Tests associés : ajout/ajustement de test_validate_channel_index_raises dans
tests/test_utils.py.
- Validation
- 2.2 : ✅ (pre-commit + black + isort + ruff + mypy + pip-audit OK)
→ Commit autorisé : ✅
Message de commit possible :
fix: clarifier message d'erreur sur index de canal
Cas : ajout d’un paramètre dans
mybci.py, oubli du formatage → ruff/black KO.
- Contexte / WBS / Murphy
- WBS ID : TPV-CLI-02 (CLI mybci – ergonomie)
- Murphy ID : M-CLI-02 (messages usage confus)
- Issue GitHub :
TPV-CLI-02 – Améliorer message d'aide de mybci.py
- Plan
- Mettre à jour le message d’aide de
mybci.py. - Corriger le formatage pour respecter black/ruff.
- Rejouer 2.2 jusqu’à tout vert.
- Checklist pré-commit (section 2)
Commandes à exécuter :
poetry run pre-commit run --all-files
poetry run black --check .
poetry run isort --check-only .
poetry run ruff check .
poetry run mypy src scripts tests
poetry run pip-audit --progress-spinner=off
make covSupposons que :
poetry run pre-commit run --all-fileséchoue surruff(ligne trop longue),- les autres commandes n’ont pas encore été rejouées après correction.
CHECKLIST 2) – état AVANT COMMIT
2.2 Pre-commit + static analysis : ❌ (ruff KO sur mybci.py)
→ Commit autorisé : ❌
- Patch proposé
L’agent propose un patch minimal pour corriger la ligne incriminée (formatage / longueur). Aucun message de commit n’est proposé.
- Validation
- 2.2 : ❌ (doit être rejoué jusqu’à succès)
- 2.3 : ❌ (doit être rejoué après correction)
« ❌ CI potentiellement en échec : commit interdit tant que la checklist 2) n’est pas entièrement verte. »
Cette charte a pour but d’aider un étudiant à écrire du code Python :
- lisible ;
- cohérent ;
- pédagogique ;
- compréhensible par un lecteur non spécialiste.
Le nommage ne sert pas seulement à faire fonctionner le code. Il sert à rendre la logique visible.
Un bon nom doit permettre de comprendre :
- ce que contient la donnée ;
- à quoi elle sert ;
- dans quel contexte elle existe ;
- sans devoir relire toute la fonction.
Un bon nom évite au lecteur de devoir deviner.
Si le lecteur doit se demander :
- “qu’est-ce que cette donnée contient ?”
- “à quoi sert-elle ?”
- “de quel domaine parle-t-on ?”
- “s’agit-il d’une valeur, d’une collection, d’un compteur, d’un index, d’un chemin, d’un score, d’un coefficient ?”
alors le nom est mauvais ou insuffisant.
Pour éviter les interprétations trop absolues, les règles de cette charte doivent être lues selon trois niveaux :
- à éviter fortement : mauvais choix dans la majorité des cas ;
- acceptable selon le contexte : peut convenir dans un code générique, scientifique ou très local ;
- recommandé : choix à privilégier dans un code pédagogique clair.
La qualité d’un nom dépend toujours :
- du domaine ;
- du public visé ;
- du niveau d’abstraction ;
- du type de code.
Nommer selon le sens réel, en fonction du contexte.
Par défaut, un bon nom décrit :
- la réalité du domaine ;
- le rôle de la donnée ;
- la nature exacte de la valeur.
Il ne doit pas, sauf besoin réel :
- décrire seulement une formule ;
- décrire seulement une structure interne ;
- utiliser un mot vague qui semble “assez correct” ;
- recopier une notation de cours sans se demander si elle reste claire ici.
x
y
z
k
m
n
theta
alpha
res
tmp
df
data
input_data
label
labels
result
configuration
row_count
column_countLes noms comme feature_matrix, target_vector, gradient,
prediction ou weights ne sont pas faux en soi,
mais deviennent insuffisants lorsqu’un nom plus métier
ou plus précis est possible.
student_age
student_house_index
current_house_index
student_count
subject_count
house_coefficients
learning_rate
predicted_house_indices
temporary_file_path
student_records
current_house_coefficient_gradient
training_settings
student_subject_scoresQuand tu choisis un nom, applique cet ordre.
Nommer la réalité du domaine.
student_house_index
exam_score
fuel_price
invoice_total
customer_emailLes exemples pédagogiques peuvent varier selon le domaine : éducation, finance, santé, logistique, industrie, web, data science, etc. La règle reste la même : nommer la réalité du domaine, pas un mot générique interchangeable.
Préciser la fonction de la donnée dans le programme.
predicted_house_index
validated_email
selected_customer_email
current_iteration
training_configurationPréciser si c’est un compteur, un chemin, une probabilité, un coefficient, etc.
student_count
model_file_path
predicted_probability
house_index
accuracy_scoreRègle par défaut : la forme interne ne doit pas être le premier niveau de nommage quand le métier est connu.
matrix
vector
row
column
array
list
dictstudent_subject_scores
house_names
student_house_indices
scores_by_house
student_countDes mots comme theta, alpha, beta, x, y, z
ne doivent être gardés que si :
- le contexte est purement mathématique ;
- le bloc est très local ;
- le lecteur visé comprend déjà cette notation.
Dans un projet pédagogique général, ils doivent être renommés.
La qualité d’un nom dépend du type de code.
Priorité maximale à la clarté immédiate. On évite fortement :
- notations mathématiques ;
- jargon trop compact ;
- noms orientés structure ;
- mots vagues.
On privilégie les noms du domaine métier.
invoice_total
customer_email
shipping_address
payment_statusCertaines notations peuvent être acceptées localement si elles sont standards pour le public visé. Mais dès que le code sort d’une démonstration courte, il faut revenir à des noms explicites.
Quand le métier n’existe pas, n’est pas connu, ou ne doit volontairement pas apparaître, des noms plus structurels peuvent être légitimes.
row_index
column_index
value_count
input_valuesPlus le contexte métier est connu, plus le nom doit être métier.
Plus le code est générique, plus un nom technique peut être acceptable.
Les identifiants Python doivent être écrits en anglais.
- c’est la convention standard en Python ;
- cela évite le mélange de langues ;
- cela améliore la réutilisabilité du code ;
- cela facilite la lecture par d’autres développeurs.
Les commentaires et docstrings peuvent être écrits en français si le public est francophone.
Mélanger les langues dans les identifiants.
maison_labels
nombre_iterations
current_thetahouse_indices
iteration_count
current_house_coefficientsUn bon nom doit être :
- clair : le sens apparaît vite ;
- simple : il reste lisible ;
- précis : il décrit bien ce qu’il représente ;
- cohérent : il suit les mêmes règles que le reste du projet ;
- stable : il ne devient pas faux au moindre changement interne ;
- orienté sens : il parle du contenu avant de parler du contenant.
Sauf cas extrêmement local.
i = 0
x = data
y = labels
m, n = scores.shapestudent_index = 0
student_subject_scores = subject_scores
student_house_indices = house_indices
student_count, subject_count = student_subject_scores.shapenum_iters
grad
preds
cfg
lbls
res
tmpiteration_count
coefficient_gradient
predicted_house_indices
training_configuration
house_indices
prediction_result
temporary_file_pathdata
value
item
object
thing
result
test
var
input
label
prediction
configuration
gradientIls ne disent pas ce que contient réellement la donnée.
student_records
predicted_house_index
input_file_path
training_loss
validated_email
current_house_coefficient_gradient
house_classifier_training_settings
student_house_indicesx
y
z
theta
alpha
beta
kstudent_subject_scores
student_house_indices
linear_scores
house_coefficients
learning_rate
regularization_strength
current_house_indexUn nom ne doit pas devenir une phrase.
normalized_student_subject_scores_with_bias_term_already_addedstudent_subject_scores_with_biasLe détail complémentaire doit aller dans :
- la docstring ;
- le commentaire ;
- le nom de la fonction ;
- la documentation.
row_count
column_count
matrix
vector
table
row_index
column_indexIls décrivent surtout la disposition interne. Ils deviennent insuffisants dès que le domaine métier est connu et qu’un nom plus concret est possible.
student_count
subject_count
student_subject_scores
student_index
subject_index
house_namesQuand le métier est inconnu, temporaire ou volontairement générique, un nom structurel peut être accepté.
value_count
row_index
column_indexMais dès que le domaine est connu, il faut renommer plus précisément.
Un mot peut être techniquement correct, mais rester insuffisant dans un code pédagogique si le contexte exige plus de précision.
data
input
label
labels
prediction
predictions
gradient
result
configuration
score
weights
bias
feature
sample
record
output
model_outputIls ne disent pas assez :
- de quoi on parle ;
- quel est le domaine ;
- quel est le rôle exact ;
- quelle valeur ils portent.
student_subject_scores
student_house_indices
predicted_house_indices
current_house_coefficient_gradient
house_classifier_training_settings
exam_score
house_coefficients
bias_term
selected_subject_names
training_example_count
student_record
predicted_house_probabilityChoisir un mot anglais ne suffit pas. Il faut choisir un mot :
- correct ;
- compréhensible ;
- non ambigu pour le public visé.
Avant de conserver un mot anglais dans un identifiant, vérifier :
- s’il ressemble fortement à un mot français ;
- si son sens technique anglais est bien le bon ;
- si un débutant francophone risque de mal l’interpréter ;
- s’il existe un terme plus explicite dans le contexte réel.
Si un doute subsiste, il faut renommer.
Un faux ami ne crée pas toujours une erreur d’exécution. Il crée souvent :
- une mauvaise compréhension ;
- un raisonnement flou ;
- un apprentissage fragile ;
- un code qui semble clair seulement pour son auteur.
Dans certains projets de machine learning, des termes comme
feature, label, weights ou bias sont standards et acceptables.
La règle pédagogique n’est pas de les interdire,
mais de vérifier s’ils sont suffisamment précis pour le lecteur visé.
Souvent trop vague.
sample_count
samples
sample_dataobservation_count
training_example_count
student_count
record_count
signal_window_countTrès ambigu.
feature_matrix
features
selected_featuresstudent_subject_scores
input_variables
selected_subject_names
predictor_valuesCorrect en ML, mais trop faible seul dans beaucoup de codes pédagogiques.
labels
target_labels
class_labelshouse_indices
target_house_indices
house_names
expected_house_indicesAcceptable, mais souvent trop vague seul.
score
scores
final_scoreexam_score
decision_score
predicted_probability
accuracy_score
house_scorePiégeux pour un francophone.
exam_score
discipline_score
student_score
score_levelUtile, mais parfois ambigu pour un francophone.
student_record
student_records
record_countTrès bon terme en data science.
observation_count
observations
customer_observationsCorrect, mais ambigu en Python orienté objet.
observation
record
training_exampleMot très ambigu.
bias
bias_valuebias_term
intercept
has_bias_term
dataset_biasMot standard en ML, parfois moins pédagogique qu’un autre.
model_weightsmodel_coefficients
house_coefficientsTrès gros faux ami.
actual_cost
actual_resultcurrent_cost
current_resultTrès dangereux.
Sens correct :
- final ;
- à terme ;
- finalement.
Sur GitHub, signifie souvent :
- problème ;
- ticket ;
- sujet de suivi.
Signifie :
- cohérence
et non :
- consistance
Signifie :
- complet ;
- exhaustif
et non :
- compréhensif
Quand un mot semble ambigu, remplace-le par un mot qui répond immédiatement à au moins une de ces questions :
- qu’est-ce que cette donnée contient ?
- de quel domaine parle-t-on ?
- s’agit-il d’une valeur ou d’une collection ?
- s’agit-il d’un compteur, d’un index, d’un score, d’une probabilité, d’un chemin, d’un coefficient ou d’un résultat ?
snake_case.py
Le nom du fichier doit refléter ce qu’il contient réellement.
student_data_loader.py
house_classifier.py
model_training.py
prediction_service.py
csv_validator.pyutils2.py
test3.py
script_final_v2.py
mon_fichier.py
stuff.pyfinalnewtemptestmiscutilssans précision
date_parser.py
string_formatter.py
path_helpers.pyPascalCase
Le nom de classe doit désigner une entité, un rôle ou un concept.
StudentRecord
HouseClassifier
CsvReader
PredictionResult
TrainingConfigurationdata
manager2
testClass
myClass
stuffsnake_case
Le nom d’une fonction doit commencer par un verbe clair.
load_training_data
validate_csv_columns
train_house_classifier
compute_accuracy_score
save_model_coefficients
predict_student_housedata_training
house_prediction
csv
model
do_stuff
process_data
handle_event
runsnake_case
Une variable doit décrire ce qu’elle contient, pas seulement son type, pas seulement sa structure, pas seulement un rôle vague.
data_frame
list_values
string_value
dict_result
matrix
labels
result
configurationstudent_records
selected_house_names
error_message
house_score_by_student
training_configuration
predicted_house_indicesLe type n’est pas le sens. La structure n’est pas le sens. Un mot générique n’est pas une explication.
UPPER_CASE
DEFAULT_LEARNING_RATE = 0.01
MAX_ITERATION_COUNT = 1000
REQUIRED_SUBJECT_NAMES = ["Arithmancy", "Astronomy", "Herbology"]
MODEL_FILE_NAME = "weights.json"Un booléen doit pouvoir se lire comme une affirmation.
is_has_can_should_was_
is_valid
has_bias_term
can_train_model
should_save_output
was_loaded_successfullyLe nom d’une collection doit indiquer ce qu’elle regroupe.
student_names
house_indices
valid_file_paths
scores_by_house
student_count_by_housescores_by_house
student_count_by_house
coefficients_by_houseLe nom doit dire clairement ce qui est compté.
student_count
subject_count
iteration_count
house_count
error_count
record_countLe nom doit préciser ce qu’il indexe.
student_index
subject_index
house_index
iteration_index
record_indexDans une boucle très courte, un nom simple mais explicite reste préférable à une lettre seule.
for student_index, student_name in enumerate(student_names):
...input_file_path
output_directory_path
model_file_path
report_url
csv_file_nameUne exception doit expliquer ce qui ne va pas.
InvalidCsvFormatError
MissingSubjectColumnError
ModelNotTrainedError
EmptyDatasetErrorCette règle résume la logique générale de la charte :
- nommer d’abord le domaine ;
- préciser ensuite le rôle ;
- préciser enfin la nature exacte de la valeur ;
- ne faire apparaître la structure interne que si elle aide réellement.
feature_matrix
target_vector
parameter_array
row_count
column_countstudent_subject_scores
student_house_indices
house_coefficients
student_count
subject_countstudent_exam_scores
student_house_indices
house_prediction_scoresLe nom doit refléter si la donnée contient une seule valeur ou plusieurs.
house_index
house_indices
student_name
student_names
prediction_score
prediction_scoreshouses_label
student
scores_listAvant de valider un nom, poser ces questions :
- Un débutant comprend-il ce que contient cette donnée ?
- Son rôle est-il clair sans relire toute la fonction ?
- Le nom exprime-t-il le sens plutôt que la formule ?
- Le nom exprime-t-il le contenu plutôt que la disposition ?
- Est-il assez précis pour éviter le doute ?
- Est-il assez court pour rester lisible ?
- Est-il cohérent avec le reste du projet ?
- Le mot choisi risque-t-il d’être ambigu pour le public visé ?
- Est-ce un nom adapté au type de code (pédagogique, métier, scientifique, générique) ?
Si une réponse pose problème, le nom doit être revu.
Cette liste peut servir de grille de relecture, de correction ou de feedback. Elle complète la charte, mais ne remplace pas le jugement de contexte. Un même nom peut être acceptable ou non selon le type de code, le public visé et le niveau de précision réellement nécessaire.
Quand tu corriges un nom, fais-le dans cet ordre :
- identifier ce que la donnée représente réellement ;
- identifier son rôle dans le programme ;
- identifier le domaine précis ;
- choisir le mot le plus simple qui reste exact ;
- ajouter seulement la précision nécessaire ;
- vérifier que le nom reste lisible ;
- vérifier qu’il n’exprime pas seulement la structure ;
- vérifier qu’il est adapté au type de code.
“C’est ce qu’on voit dans le cours, donc je garde
X,y,theta.”
“C’est mieux que
x, doncinput_data,labels,resultsuffisent.”
“Le lecteur doit comprendre ce que cette donnée représente, sans connaître la formule, sans deviner le domaine, et sans devoir interpréter un mot vague.”
- utiliser l’anglais pour les identifiants ;
- nommer selon le sens réel ;
- préférer le métier à la structure ;
- choisir des mots simples ;
- préciser ce qui est compté ;
- utiliser un verbe clair pour les fonctions ;
- nommer les booléens comme des affirmations ;
- rester cohérent dans tout le projet ;
- adapter le nom au type de code.
- lettres seules ;
- abréviations ;
- jargon inutile ;
- mélange de langues ;
- noms trop vagues ;
- noms mathématiques ;
- noms orientés structure ;
- mots corrects mais flous ;
- détails techniques inutiles dans le nom.
Par défaut, un bon nom doit dire :
- ce que c’est ;
- ce que ça contient ;
- à quoi ça sert ;
- de quel domaine on parle.
Et si nécessaire, il doit aussi préciser :
- s’il s’agit d’une valeur ou d’une collection ;
- s’il s’agit d’un compteur, d’un index, d’un score, d’un chemin, d’une probabilité ou d’un coefficient.
S’il n’aide pas réellement le lecteur à comprendre, il faut le renommer.
Le nommage n’est pas une décoration. C’est une partie de l’explication du programme.
Le bon nom n’ajoute pas du style : il retire du doute.
x, y, z, i, j, k, df, tmp, res, obj, val, data
label, labels, result, prediction, predictions
gradient, configuration, matrix, vector, row, columnstudent_subject_scores
student_house_indices
current_house_index
student_count
subject_count
house_coefficients
predicted_house_indices
is_valid
output_file_path
training_configuration
current_house_coefficient_gradientload_student_records
validate_input_file
train_house_classifier
predict_house_indices
save_prediction_resultsStudentRecord
HouseClassifier
TrainingConfiguration
PredictionResultDEFAULT_LEARNING_RATE
MAX_ITERATION_COUNT
REQUIRED_SUBJECT_NAMES
MODEL_FILE_NAMELorsque tu génères, modifies ou réécris du code, applique strictement les règles suivantes.
Les commentaires doivent documenter chaque ligne de code.
Le but est d’avoir un commentaire juste au-dessus de chaque ligne, y compris pour les imports, constantes, affectations, conditions, retours, appels de fonctions, transformations intermédiaires, boucles, compréhensions, structures de contrôle et expressions composées.
Cette documentation doit aider :
- un développeur qui reprend le code plus tard ;
- un mainteneur occasionnel qui revient dessus dans 3 ou 5 ans ;
- un lecteur non développeur qui doit malgré tout comprendre le rôle local de chaque ligne ;
- un futur modificateur qui doit identifier rapidement où intervenir pour changer un comportement précis.
Le code reste la source principale d’exécution, mais le commentaire devient la source principale d’explication locale.
Le code doit rester lisible par lui-même.
Le commentaire doit rendre la lecture, la maintenance et la modification
plus sûres.
Chaque ligne doit être commentée.
La priorité reste, dans cet ordre :
- un meilleur nommage ;
- une variable intermédiaire explicite ;
- une extraction de fonction ;
- un commentaire au-dessus de la ligne.
Autrement dit :
- on ne garde jamais un code opaque sous prétexte qu’il sera commenté ;
- on améliore d’abord le code ;
- puis on documente chaque ligne pour rendre son rôle clair, même à un lecteur non expert.
Pour chaque ligne, le commentaire doit chercher à fournir, dans cet ordre de priorité, le niveau le plus utile :
- le pourquoi de la ligne ;
- le rôle utile de la ligne dans le bloc ou l’algorithme ;
- l’effet concret utile de la ligne sur les données, le contrat, la structure ou le flux ;
- le point de repérage de maintenance : ce que cette ligne pilote, verrouille, influence ou contraint.
Autrement dit :
- si un vrai pourquoi existe, il faut l’écrire ;
- sinon, on documente à quoi sert la ligne ici ;
- sinon, on documente ce qu’elle change concrètement ;
- sinon, on documente où revenir pour modifier ce comportement.
Chaque commentaire doit apporter au moins une des informations suivantes :
- pourquoi cette ligne existe sous cette forme ;
- pourquoi cette implémentation a été retenue ici ;
- quel rôle exact elle joue dans le flux ;
- quel effet concret elle produit sur les données ou le comportement ;
- quel risque elle évite ;
- quelle garantie elle protège ;
- quelle contrainte elle respecte ;
- quel contrat elle préserve ;
- quelle robustesse, stabilité ou compatibilité elle apporte ;
- quel point de modification futur elle constitue.
Un commentaire ne doit jamais :
- se contenter de recopier mot à mot la ligne ;
- paraphraser trivialement la syntaxe ;
- être faux ou approximatif ;
- nommer seulement l’API sans expliquer son intérêt ;
- être décoratif ;
- masquer un code inutilement opaque qu’on aurait pu mieux nommer.
Puisque l’objectif est d’avoir un commentaire sur chaque ligne, on n’utilise plus la règle :
« ne commente pas si la ligne est évidente »
À la place, on applique la règle suivante :
Même si la ligne est simple, elle doit être documentée, avec le niveau d’explication le plus utile disponible.
Cela signifie :
- une ligne importante reçoit un commentaire riche ;
- une ligne simple peut recevoir un commentaire court ;
- une ligne évidente ne doit pas rester sans commentaire ;
- mais son commentaire doit quand même aider la lecture future.
Avant d’écrire un commentaire, vérifie que :
- il aide à comprendre pourquoi, à quoi sert, ce que change ou où modifier cette ligne ;
- il apporte au moins une information utile absente de la simple lecture brute du code ;
- il reste intelligible pour un lecteur non expert ;
- il améliore réellement la maintenance, le diagnostic, la robustesse ou la localisation d’un futur changement.
Si un vrai “pourquoi” n’existe pas, n’abandonne pas le commentaire : descends au niveau suivant de la hiérarchie (rôle utile, effet concret, repérage de maintenance).
Un bon commentaire peut documenter :
- une intention de conception ;
- une contrainte technique ou métier ;
- un invariant à préserver ;
- un risque évité ;
- un compromis assumé ;
- une robustesse recherchée ;
- une stabilité de test ;
- une compatibilité inter-OS ou inter-environnements ;
- une exigence de maintenabilité ;
- une contrainte de performance ;
- un diagnostic exploitable ;
- un contrat d’interface ;
- un comportement attendu en cas d’erreur ;
- une normalisation volontaire ;
- une convention retenue pour fiabiliser le système ;
- une hypothèse d’entrée ou de format ;
- une limite connue ;
- une dette technique explicitement assumée ;
- une contrainte imposée par une API, un protocole, un format ou un outil ;
- la structure des données manipulées ;
- le point exact à modifier pour changer un comportement.
Le commentaire doit être formulé, selon le cas, comme :
- une justification ;
- une explication de rôle ;
- une explication d’effet concret ;
- une indication de repérage pour maintenance ;
- une contrainte, une garantie, une hypothèse ou une limite utile.
Formulations adaptées :
- Pour garantir…
- Pour éviter…
- Pour préserver…
- Pour stabiliser…
- Pour fiabiliser…
- Pour conserver…
- Pour limiter…
- Pour protéger…
- Pour maintenir…
- Pour distinguer clairement…
- Pour garder un contrat cohérent…
- Pour rendre le diagnostic exploitable…
- Pour éviter qu’un cas limite casse…
- Pour imposer une représentation canonique…
- Pour réduire une ambiguïté de comportement…
- Cette ligne prépare…
- Cette ligne aligne…
- Cette ligne réutilise…
- Cette ligne verrouille…
- Cette ligne pilote…
- Cette ligne sert de point d’entrée pour…
- C’est ici qu’il faut intervenir pour modifier…
- Convention imposée par…
- Compatibilité requise avec…
- Limite volontaire : …
- Hypothèse : …
- Précondition : …
- Postcondition attendue : …
Formulations à éviter en général :
- Importe…
- Initialise…
- Calcule…
- Retourne…
- Vérifie…
- Exécute…
- Normalise…
- Capture…
- Construit…
- Ajoute…
- Supprime…
- Transforme…
- Affiche…
Ces verbes ne sont pas interdits absolument, mais ils sont insuffisants s’ils décrivent seulement l’action visible sans expliquer son intérêt local.
Quand une ligne contient un attribut, une méthode, une fonction, un module,
une librairie ou une notation dont le nom n’est pas transparent par lui-même
(ex. symbole court, abréviation, convention mathématique, API cryptique,
notation implicite comme .T, .dot, .iloc, np, pd, etc.),
le commentaire peut et doit expliciter :
- ce que cet élément fait concrètement ;
- à quoi il sert ici ;
- pourquoi cette opération est utilisée dans ce contexte ;
- où il faut intervenir si l’on veut changer ce comportement.
Cette exception est importante, car certaines notations sont compactes pour l’expert, mais opaques pour un futur lecteur ou modificateur.
Quand un nom est opaque, le commentaire peut préciser :
- ce que l’élément fait en termes simples et concrets ;
- quel changement de représentation il produit ;
- quel rôle mathématique, algorithmique ou structurel il joue ;
- pourquoi cette transformation est nécessaire ici ;
- quelle compatibilité de dimensions, de contrat ou de représentation elle garantit ;
- quel risque d’ambiguïté elle lève pour le lecteur ;
- à quel endroit il faudra revenir pour modifier cette logique.
Pour des notations très compactes comme .T ou .dot,
il est autorisé de mentionner explicitement leur effet concret.
Exemples de reformulations plus parlantes :
.T: échange lignes et colonnes pour réorienter la lecture des données ;.dot: combine des valeurs alignées entre deux structures numériques pour produire un score, une somme pondérée ou une agrégation vectorisée.
On ne se limite donc pas au terme académique ; on cherche une formulation compréhensible et exploitable.
Ne pas écrire un commentaire qui :
- se contente de nommer l’API ;
- répète un terme technique sans le rendre plus clair ;
- décrit mécaniquement la syntaxe sans expliquer son intérêt ici ;
- oublie le rôle de la ligne dans le calcul ou dans la maintenance.
Quand c’est utile, on peut combiner :
- l’effet concret ;
- la signification conceptuelle ;
- la raison locale ;
- l’impact maintenance.
Exemples de formulations adaptées :
- Pour échanger lignes et colonnes avant d’agréger l’erreur par variable
- Pour combiner chaque erreur avec la variable correspondante
- Pour produire la somme pondérée utilisée par la mise à jour des poids
- C’est ici que se joue l’alignement entre variables et erreurs
- Modifier cette ligne change la manière dont les contributions sont agrégées
Comme cette documentation doit aussi servir à un futur lecteur qui voudra corriger ou faire évoluer le code, chaque commentaire peut indiquer, quand c’est pertinent :
- ce que la ligne pilote ;
- ce que sa modification changera ;
- quel comportement dépend d’elle ;
- quelle donnée, quelle règle ou quel format elle verrouille ;
- dans quel bloc revenir pour changer une logique précise.
Exemples :
- C’est ici que l’ordre des colonnes est figé
- Modifier cette ligne changera la normalisation appliquée au test
- Cette ligne impose le nom final de la colonne exportée
- C’est ce bloc qu’il faut ajuster pour changer l’imputation des valeurs manquantes
Obligatoire au-dessus de chaque ligne.
Autorisé en plus lorsqu’un ensemble de lignes participe à une même intention forte.
Le commentaire de bloc ne remplace pas les commentaires de ligne ; il les complète.
Réservée aux modules, classes et fonctions. Elle documente le contrat global.
Autorisé lorsqu’il faut signaler :
- une convention imposée ;
- une hypothèse non évidente ;
- une limite volontaire ;
- une compatibilité requise ;
- une dette technique connue.
- Ajoute un commentaire au-dessus de chaque ligne de code.
- Le commentaire doit respecter l’indentation du bloc.
- Langue : français.
- Les termes techniques anglais sont autorisés uniquement pour :
- les noms d’API ;
- les types ;
- les constantes ;
- les mots-clés du langage ;
- les noms de fonctions, classes, modules ou outils.
- 80 caractères maximum par ligne de commentaire.
- Si une explication complète dépasse 80 caractères, la répartir sur plusieurs lignes de commentaire.
- Interdit :
- commentaire en fin de ligne ;
- commentaire sous la ligne ;
- paraphrase brute du code ;
- commentaire décoratif ;
- commentaire faux ;
- commentaire générique sans utilité de lecture ou de maintenance ;
- commentaire inventant une justification absente du contexte.
Si un commentaire existant est trop faible, réécris-le pour exprimer à la place :
- pourquoi la ligne existe ;
- à quoi elle sert dans le bloc ;
- ce qu’elle change concrètement ;
- ce qu’elle protège ;
- ce qu’elle impose ;
- ce qu’un futur modificateur doit savoir avant d’y toucher ;
- où intervenir pour modifier le comportement concerné.
Si un vrai “pourquoi” ne peut pas être formulé, le commentaire doit au minimum documenter le rôle utile ou l’effet concret de la ligne.
Utilise des docstrings uniquement pour :
- les modules ;
- les classes ;
- les fonctions.
Les docstrings doivent couvrir, selon le contexte :
- le but global ;
- les paramètres ;
- la valeur de retour ;
- les erreurs levées ;
- le contrat global d’utilisation ;
- les préconditions utiles ;
- les postconditions utiles ;
- les effets de bord notables ;
- les conventions de format, d’unité ou de représentation si nécessaires.
Les docstrings ne remplacent pas les commentaires ligne par ligne.
Quand tu traites du code :
- améliore d’abord le nommage si le code est ambigu ;
- introduis une variable intermédiaire si elle clarifie l’intention ;
- extrais une fonction si cela rend le bloc plus lisible ;
- ajoute ensuite un commentaire au-dessus de chaque ligne ;
- formule en priorité le pourquoi ;
- à défaut, formule le rôle utile de la ligne ;
- à défaut, formule son effet concret ;
- à défaut, formule son intérêt pour un futur modificateur ;
- n’invente jamais une justification absente du contexte ;
- garde des commentaires exacts, utiles et lisibles.
# On importe Path
from pathlib import Path
# On supprime les espaces
normalized_url = url.strip()
# On retourne 0
return 0Pourquoi c’est interdit :
- le commentaire répète l’action visible ;
- il n’aide ni la maintenance, ni la compréhension ;
- il ne dit pas pourquoi la ligne existe ici.
# .T transpose la matrice
transposed_scores = student_scores.T
# .dot fait un produit matriciel
error_sum = transposed_scores.dot(prediction_error_by_student)Pourquoi c’est interdit :
- le terme technique est répété sans être rendu clair ;
- le rôle local dans l’algorithme n’est pas expliqué ;
- un futur modificateur ne sait pas ce que changerait cette ligne.
# On crée un parser
argument_parser = argparse.ArgumentParser()
# On ajoute un argument
argument_parser.add_argument("--out")
# On parse les arguments
return argument_parser.parse_args()Pourquoi c’est interdit :
- chaque ligne est commentée ;
- mais la documentation reste descriptive et superficielle ;
- elle ne répond ni au pourquoi, ni au rôle, ni au repérage maintenance.
# On évite une dépendance au shell et aux séparateurs propres a l'OS
from pathlib import Path
# On assainit l'entree pour eviter qu'un espace parasite fausse la validation
normalized_url = url.strip()
# On garde un code retour neutre car l'erreur a deja ete explicitee avant
return 0# On reechange la lecture des donnees pour raisonner par variable
# plutot que par observation avant l'agregation
transposed_scores = student_scores.T
# On combine chaque variable avec les erreurs correspondantes
# pour produire la somme utilisee par la mise a jour
error_sum = transposed_scores.dot(prediction_error_by_student)# Cette ligne fige le nom de la colonne exportee ;
# c'est ici qu'il faut intervenir pour changer le schema de sortie
prediction_output = pd.DataFrame(
{"Index": index_list_of_students, "Hogwarts House": predicted_house_names}
)
# Cette ligne persiste le resultat final sans index pandas,
# ce qui maintient le format attendu par l'evaluateur
prediction_output.to_csv(output_csv_path, index=False)# On recupere le nombre d'observations pour dimensionner la colonne de biais
student_count = standardized_students_discipline_scores.shape[0]
# On prepare une colonne de 1 pour reproduire la convention du modele appris
bias_column = np.ones((student_count, 1))
# On assemble biais et variables normalisees dans l'ordre attendu par les poids
students_discipline_scores_with_bias = np.hstack(
# Cette sous-structure preserve la colonne de biais en premiere position
[bias_column, standardized_students_discipline_scores]
)# On parcourt chaque discipline pour reappliquer la logique du train colonne par colonne
for discipline_index, discipline_name in enumerate(students_discipline_scores.columns):
# Cet indice sert a retrouver la bonne statistique de reference
reference_average_score = average_discipline_scores[discipline_index]
# On cible explicitement la colonne a corriger pour garder le schema intact
students_discipline_scores[discipline_name] = (
# On remplace les valeurs manquantes par la moyenne du train
# pour eviter une fuite de donnees provenant du jeu de test
students_discipline_scores[discipline_name].fillna(
# C'est ici qu'il faut intervenir si la strategie d'imputation change
reference_average_score
)
)# On verrouille la presence d'un identifiant stable avant toute prediction
if "Index" not in raw_students_dataset.columns:
# Ce message cible directement la cause pour accelerer le diagnostic
raise ValueError("La colonne 'Index' est manquante dans le fichier CSV.")Chaque ligne doit être commentée.
Le meilleur commentaire explique pourquoi la ligne existe.
Si ce niveau n’est pas accessible, le commentaire doit au moins expliquer :
- à quoi sert la ligne ici ;
- ce qu’elle change concrètement ;
- ou pourquoi un futur mainteneur devra revenir à cet endroit.
Une ligne simple peut recevoir un commentaire court. Une ligne sensible doit recevoir un commentaire plus riche. Mais aucune ligne de code ne doit rester sans commentaire.