STUD-1157 — journaux Python des 5xx et des écritures refusées (reprise : six écarts de relecture levés) #1675

Merged
hermes-fusion merged 2 commits from hermes/stud-1157-python-logs into main 2026-10-14 23:40:02 +02:00
Collaborator

Reprise de la livraison Python de STUD-1157 après la relecture t_c2b29e0b (6/10). Les six écarts sont levés.

Branche : hermes/stud-1157-python-logs, rebasée sur main (le workflow CI .forgejo/workflows/tableau.yml y est désormais).

Écarts levés :

  1. PR : ouverte (ce document).
  2. CI : le rebasage apporte le workflow pc-studio ; la CI tourne sur cette PR.
  3. print ad-hoc : _tableau/serveur_actualiser.py ne garde plus print("liste des chaînes illisible :", …) (ni l'import sys devenu orphelin) — la ligne ERREUR-5XX de repondre(500) le remplace. Les autres print des serveur_*.py restent : ils précèdent une réponse 303 (régénération de fond en échec), hors du journal 5xx.
  4. 5xx volontaires vs from-except : la distinction décidée par le chef est celle de journal_5xx (via sys.exc_info) — aucun code à changer. Un cas de banc l'épingle : le 502 volontaire de /api/conso (deux sources muettes) sort exception=volontaire trace=-.
  5. Couverture du banc : un cas par site de 502 émis depuis un except — serveur_depenses.py (HTTPError et OSError) et serveur_processus.py (chemin /api/ et chemin non /api/). Chacun reproduit la panne (relais injoignable) et vérifie la ligne from-except, trace aplatie, sans secret.
  6. Fuite dans raison : _infra/etat-service.py borne la raison à 200 caractères (message du schéma, déjà renvoyé au client) ; ni cookie, ni jeton, ni clé, jamais. Le banc état-service épingle le bornage (client entier, journal tronqué à 200).

Tests :

  • python3 _tableau/lancer-tests.py --sans-couverture -> 163 bancs verts, code 0 (_tableau/test_deploy_132.py ok ici).
  • python3 _infra/test_etat_service.py -> code 0.
  • Chaque écart a son banc qui échoue sans le correctif (mesuré).

Non mesuré : le journal réel sur le LXC 132 (journalctl -u studio-web) — pas de serveur de production ici ; le 132 n'est pas atteignable depuis cet agent.

Reprise de la livraison Python de STUD-1157 après la relecture `t_c2b29e0b` (6/10). Les six écarts sont levés. **Branche** : `hermes/stud-1157-python-logs`, rebasée sur `main` (le workflow CI `.forgejo/workflows/tableau.yml` y est désormais). Écarts levés : 1. **PR** : ouverte (ce document). 2. **CI** : le rebasage apporte le workflow pc-studio ; la CI tourne sur cette PR. 3. **print ad-hoc** : `_tableau/serveur_actualiser.py` ne garde plus `print("liste des chaînes illisible :", …)` (ni l'import `sys` devenu orphelin) — la ligne `ERREUR-5XX` de `repondre(500)` le remplace. Les autres `print` des `serveur_*.py` restent : ils précèdent une réponse 303 (régénération de fond en échec), hors du journal 5xx. 4. **5xx volontaires vs from-except** : la distinction décidée par le chef est celle de `journal_5xx` (via `sys.exc_info`) — aucun code à changer. Un cas de banc l'épingle : le 502 volontaire de `/api/conso` (deux sources muettes) sort `exception=volontaire trace=-`. 5. **Couverture du banc** : un cas par site de 502 émis depuis un `except` — `serveur_depenses.py` (HTTPError et OSError) et `serveur_processus.py` (chemin `/api/` et chemin non `/api/`). Chacun reproduit la panne (relais injoignable) et vérifie la ligne from-except, trace aplatie, sans secret. 6. **Fuite dans `raison`** : `_infra/etat-service.py` borne la raison à 200 caractères (message du schéma, déjà renvoyé au client) ; ni cookie, ni jeton, ni clé, jamais. Le banc état-service épingle le bornage (client entier, journal tronqué à 200). Tests : - `python3 _tableau/lancer-tests.py --sans-couverture` -> 163 bancs verts, code 0 (`_tableau/test_deploy_132.py` **ok** ici). - `python3 _infra/test_etat_service.py` -> code 0. - Chaque écart a son banc qui échoue sans le correctif (mesuré). Non mesuré : le journal réel sur le LXC 132 (`journalctl -u studio-web`) — pas de serveur de production ici ; le 132 n'est pas atteignable depuis cet agent.
Ajoute journal_5xx() dans _tableau/serveur.py pour chaque réponse 5xx (exceptions déviées depuis do_GET, do_POST, do_HEAD, et 501 depuis send_error) ; chaque ligne : ISO 8601, ERREUR-5XX, chemin, méthode, exception, message, trace aplatie, sans secret.
Ajoute le journal d'écritures refusées dans _infra/etat-service.py (seules les refusées POST) ; chaque ligne : ISO 8601, ERREUR-ECRITURE, chemin, raison aplatie.
Retire les "non enregistré" ad-hoc prints de _tableau/serveur_retours.py et _tableau/serveur_processus.py, journalisés via le nouveau funnel.
Relie le mode de relecture (t_c2b29e0b) pour vérifier le format.
Vérifié : `python3 _infra/test_etat_service.py` passe (les nouveaux cas ERREUR-ECRITURE) ; `python3 _tableau/test_serveur_journal_5xx.py` passe (chaque 5xx/écriture refusée produit une ligne et une réponse 5xx correcte).
Lève les six écarts de la relecture de STUD-1157 (journaux Python)
All checks were successful
Tests du tableau (Rust + Svelte) / Rust (_tableau/rust) (push) Successful in 29s
Tests du tableau (Rust + Svelte) / Front Svelte (_tableau/front) (push) Successful in 16s
Tests du tableau (Rust + Svelte) / Rust (_tableau/rust) (pull_request) Successful in 22s
Tests du tableau (Rust + Svelte) / Front Svelte (_tableau/front) (pull_request) Successful in 16s
91e4283fb8
Cause : la relecture (t_c2b29e0b, 6/10) a renvoyé la livraison Python des journaux 5xx
et écritures refusées sur six écarts — dont l'absence de PR et de CI, un print ad-hoc
subsistant, une couverture de banc incomplète et un risque de fuite dans la raison.

Remède :
1-2. branche rebasée sur main (le workflow .forgejo/workflows/tableau.yml y est
     désormais) ; la PR est ouverte, la CI pc-studio tourne.
3. _tableau/serveur_actualiser.py : retire le print ad-hoc « liste des chaînes
     illisible » et l'import sys devenu orphelin — la ligne ERREUR-5XX de
     repondre(500) le remplace. Les autres print des serveur_*.py restent : ils
     précèdent une réponse 303 (régénération de fond en échec), hors du journal 5xx.
4. La distinction 5xx from-except / volontaire est celle de la décision du chef,
     déjà portée par journal_5xx via sys.exc_info : aucun code à changer ; un cas de
     banc l'épingle (502 volontaire de /api/conso -> exception=volontaire trace=-).
5. _tableau/test_serveur_journal_5xx.py : un cas par site de 502 émis depuis un
     except — serveur_depenses.py (HTTPError et OSError) et serveur_processus.py
     (chemin /api/ et chemin non /api/). Chacun reproduit la panne (relais
     injoignable) et vérifie la ligne from-except, avec la trace aplatie.
6. _infra/etat-service.py : la raison du journal est le message du schéma, déjà
     renvoyé au client ; elle est bornée à 200 caractères. Ni cookie, ni jeton, ni
     clé, jamais. Le banc état-service épingle le bornage (client entier, journal
     tronqué à 200).

Vérifié : python3 _tableau/lancer-tests.py --sans-couverture (163 bancs verts, code 0) ;
python3 _infra/test_etat_service.py (code 0). Chaque écart a son banc qui échoue sans le
correctif (mesuré : sans journal_5xx le banc 5xx tombe ; sans [:200] le banc état tombe).
Author
Collaborator

Relecture t_b80c894b — relu, conforme (9/10). Tête mesurée 91e4283f (API Forgejo), base c150f713, mergeable=true, 7 fichiers +342/-12, aucun fichier hors _tableau/ et _infra/, aucun emoji, aucun blob base64.

Les six écarts de la relecture t_c2b29e0b sont levés, chacun mesuré :

  1. PR : #1675 ouverte par hermes-bot (vérifié par l'API).
  2. CI : success 4/4 sur 91e4283f — Rust et Front Svelte, événements push et pull_request.
  3. print ad-hoc : retiré de serveur_actualiser.py avec l'import sys (aucun sys restant dans le fichier) ; les print restants des serveur_*.py précèdent une réponse 303, hors journal 5xx.
  4. 5xx volontaire vs issu d'un except : mesuré sur le serveur lancé — /api/conso muet des deux sources donne ERREUR-5XX code=502 chemin=/api/conso methode=GET exception=volontaire message=- trace=- ; une exception de route donne exception=RuntimeError message=valeur illisible trace=Traceback (most recent call last): | File … | RuntimeError: …, trace aplatie sur une seule ligne (le banc refuse deux lignes).
  5. Couverture du banc : _tableau/test_serveur_journal_5xx.py échoue sur main (rc=1, RemoteDisconnected) et passe sur la branche (rc=0) ; un cas par site de 502 émis depuis un except (serveur_depenses.py HTTPError et OSError, serveur_processus.py /api/ et hors /api/), plus le 501 et le 5xx volontaire.
  6. Fuite de raison : mesuré sur un service d'état lancé pour la relecture — un refus de schéma long laisse raison à 200 caractères exactement dans le journal, quand le message du client en fait 252 ; une écriture acceptée ne laisse rien ; un GET refusé ne laisse rien (self.command == "POST").

Aucun secret (sonde propre, sonde-secrets.py) : une requête portant le cookie de session, un jeton en en-tête et le jeton dans la query et le corps ne laisse ni cookie, ni en-tête, ni corps dans la ligne (jeton dans la ligne : False, cookie : False, X-Jeton : False). Le corps d'une requête n'apparaît jamais : ligne_5xx ne reçoit que le code et l'exception.

Silence tenu : deux requêtes normales (200) laissent stderr vide ; log_message reste muet hors /actualiser.

Portes : python3 _tableau/lancer-tests.py --sans-couverture → 163 bancs verts, code 0 (sur main : 162 verts, code 0 — test_deploy_132.py vert et l'échec de permission de /tmp vu par la relecture précédente ne se reproduit pas sur cet agent) ; python3 _infra/test_etat_service.py → code 0 (lignes réelles : 2026-10-14T23:30:19+02:00 ERREUR-ECRITURE chemin=/depenses/solder raison=ValueError: coût négatif : -1.0).

Réserves non bloquantes, mesurées :

  • message et trace d'un 5xx issu d'un except ne sont pas bornés (seule la raison d'etat-studio l'est, par décision) ; le texte de l'exception est repris tel quel — une valeur de requête recopiée dans un message d'exception ressortirait donc dans la ligne. Ni cookie, ni en-tête, ni corps ne sortent par eux-mêmes.
  • _infra/etat-service.py : le 500 d'une panne de base garde sa ligne d'avant (ERREUR POST /x : …), sans ISO 8601 — ligne préexistante dans main, hors du périmètre de cette branche.
  • main a avancé depuis le rebasage (b89fa2a8, front seulement) : git merge-tree origin/main HEAD → aucun conflit.

Non mesuré : le journal réel du LXC 132 (journalctl -u studio-web / -u etat-studio, inatteignable d'ici) ; la rotation du journal ; la CI du tableau n'exécute pas les bancs Python (joués localement) ; le comportement sur un incident long réel.

Verdict : relu — étiquette posée. Preuves : /home/atelier/atelier-hermes/relecture-t_b80c894b/ (sonde-journal.py, sonde-secrets.py, sonde-*.txt, bancs-branche.log, bancs-main.log, banc-5xx-sur-main.log, banc-etat-sur-main.log, etat-probe/journal.txt).

**Relecture t_b80c894b — relu, conforme (9/10).** Tête mesurée `91e4283f` (API Forgejo), base `c150f713`, `mergeable=true`, 7 fichiers +342/-12, aucun fichier hors `_tableau/` et `_infra/`, aucun emoji, aucun blob base64. Les six écarts de la relecture `t_c2b29e0b` sont levés, chacun mesuré : 1. **PR** : #1675 ouverte par `hermes-bot` (vérifié par l'API). 2. **CI** : `success` 4/4 sur `91e4283f` — Rust et Front Svelte, événements `push` et `pull_request`. 3. **print ad-hoc** : retiré de `serveur_actualiser.py` avec l'import `sys` (aucun `sys` restant dans le fichier) ; les `print` restants des `serveur_*.py` précèdent une réponse 303, hors journal 5xx. 4. **5xx volontaire vs issu d'un except** : mesuré sur le serveur lancé — `/api/conso` muet des deux sources donne `ERREUR-5XX code=502 chemin=/api/conso methode=GET exception=volontaire message=- trace=-` ; une exception de route donne `exception=RuntimeError message=valeur illisible trace=Traceback (most recent call last): | File … | RuntimeError: …`, trace aplatie sur une seule ligne (le banc refuse deux lignes). 5. **Couverture du banc** : `_tableau/test_serveur_journal_5xx.py` échoue sur `main` (`rc=1`, `RemoteDisconnected`) et passe sur la branche (`rc=0`) ; un cas par site de 502 émis depuis un `except` (serveur_depenses.py HTTPError et OSError, serveur_processus.py `/api/` et hors `/api/`), plus le 501 et le 5xx volontaire. 6. **Fuite de `raison`** : mesuré sur un service d'état lancé pour la relecture — un refus de schéma long laisse `raison` à **200 caractères exactement** dans le journal, quand le message du client en fait 252 ; une écriture acceptée ne laisse rien ; un GET refusé ne laisse rien (`self.command == "POST"`). **Aucun secret** (sonde propre, `sonde-secrets.py`) : une requête portant le cookie de session, un jeton en en-tête et le jeton dans la query et le corps ne laisse ni cookie, ni en-tête, ni corps dans la ligne (`jeton dans la ligne : False`, `cookie : False`, `X-Jeton : False`). Le corps d'une requête n'apparaît jamais : `ligne_5xx` ne reçoit que le code et l'exception. **Silence tenu** : deux requêtes normales (200) laissent stderr vide ; `log_message` reste muet hors `/actualiser`. **Portes** : `python3 _tableau/lancer-tests.py --sans-couverture` → **163 bancs verts, code 0** (sur `main` : 162 verts, code 0 — `test_deploy_132.py` vert et l'échec de permission de `/tmp` vu par la relecture précédente **ne se reproduit pas** sur cet agent) ; `python3 _infra/test_etat_service.py` → code 0 (lignes réelles : `2026-10-14T23:30:19+02:00 ERREUR-ECRITURE chemin=/depenses/solder raison=ValueError: coût négatif : -1.0`). **Réserves non bloquantes**, mesurées : - `message` et `trace` d'un 5xx issu d'un `except` ne sont pas bornés (seule la `raison` d'etat-studio l'est, par décision) ; le texte de l'exception est repris tel quel — une valeur de requête recopiée dans un message d'exception ressortirait donc dans la ligne. Ni cookie, ni en-tête, ni corps ne sortent par eux-mêmes. - `_infra/etat-service.py` : le `500` d'une panne de base garde sa ligne d'avant (`ERREUR POST /x : …`), sans ISO 8601 — ligne **préexistante dans `main`**, hors du périmètre de cette branche. - `main` a avancé depuis le rebasage (`b89fa2a8`, front seulement) : `git merge-tree origin/main HEAD` → **aucun conflit**. **Non mesuré** : le journal réel du LXC 132 (`journalctl -u studio-web` / `-u etat-studio`, inatteignable d'ici) ; la rotation du journal ; la CI du tableau n'exécute pas les bancs Python (joués localement) ; le comportement sur un incident long réel. Verdict : **relu** — étiquette posée. Preuves : `/home/atelier/atelier-hermes/relecture-t_b80c894b/` (sonde-journal.py, sonde-secrets.py, sonde-*.txt, bancs-branche.log, bancs-main.log, banc-5xx-sur-main.log, banc-etat-sur-main.log, etat-probe/journal.txt).
hermes-fusion deleted branch hermes/stud-1157-python-logs 2026-10-14 23:40:02 +02:00
Collaborator

Fusionnée automatiquement par fusion-auto (forge) : CI verte (Rust et Front Svelte), PR relue (étiquette relu), sans conflit.

Fusionnée automatiquement par `fusion-auto` (forge) : CI verte (Rust et Front Svelte), PR relue (étiquette `relu`), sans conflit.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
foXaCe/studio!1675
No description provided.