STUD-1157 — service-tableau : POST et GET /api/erreurs-page, journal tournant des erreurs de la page #1642

Merged
hermes-fusion merged 1 commit from hermes/stud-1157-backend-erreurs into main 2026-10-15 07:50:27 +02:00
Collaborator

Ce que la carte livre

Deux routes nouvelles sur service-tableau (Rust, _tableau/rust) : un POST qui reçoit les erreurs de la page et les écrit dans un journal tournant, un GET qui rend les 24 dernières heures pour l'onglet Processus.

Nouvelle route : /api/erreurs-page (contrat pour le front)

POST /api/erreurs-page — corps JSON, tel que l'envoie front/src/lib/erreurs-navigateur.js :

{"message": "TypeError: x is not a function", "pile": "…", "onglet": "/processus", "version": "abc123", "ecran": "1920x1080", "navigateur": "Mozilla/5.0"}

Réponses : 200 {"ok":true} écrit ; 200 {"ok":true,"doublon":true} si la même erreur du même client vient d'être écrite ; 400 corps illisible, message vide, ou champ reconnu qui n'est pas du texte ; 429 au onzième envoi de la minute ; 500 journal non écrit, avec la raison en clair.

GET /api/erreurs-page — les 24 dernières heures, regroupées par message (clé du front : espaces comprimés, minuscules), le plus récent d'abord :

{"depuis_h": 24, "groupes": 2, "total_24h": 2,
 "erreurs": [{"message": "…", "compte": 1, "derniere": "2026-10-14T18:52:07+00:00", "il_y_a_s": 0,
              "pile": "…", "onglet": "…", "version": "…", "ecran": "…", "navigateur": "…"}]}

Le journal est /opt/studio/journaux/erreurs-page.jsonl (SERVICE_JOURNAL_ERREURS pour le déplacer), une ligne JSON par erreur, quand (ISO 8601 UTC) et ts. Aucune clé hors des six ci-dessus n'est écrite — donc aucun secret, et l'adresse du client (qui sert à la limite et au dédoublonnage) n'est jamais écrite. Tournant passé 4 Mo : les 10 000 dernières lignes restent, réécrites par renommage.

Preuves

La panne d'avant, mesurée : sur le binaire d'origin/main (c5e7c4a2), lancé :

POST /api/erreurs-page → HTTP/1.1 405 Method Not Allowed   (« lecture seule »)
GET  /api/erreurs-page → HTTP/1.1 404 Not Found
journal /opt/studio/journaux/ : absent

Le banc rejoué sur origin/main échoue de la même façon (405 lecture seule), et passe sur la branche.

Sur la branche, même binaire, mêmes commandes :

POST {"message":"TypeError: apres", …, "jeton":"un-secret"} → 200 {"ok":true}
POST (même erreur)                                          → 200 {"ok":true,"doublon":true}
POST {"message":"RangeError: autre"}                        → 200 {"ok":true}
GET  /api/erreurs-page                                      → 200 {"depuis_h":24,"groupes":2,"total_24h":2,…}
journal  2 lignes, aucune trace de « un-secret »

cargo test --release --locked (branche, commit ab165f74) : 53 cas, 0 échec, code 0, dont les 4 nouveaux de service/tests/erreurs_page.rs, qui lancent le vrai binaire et lui parlent par TCP (écriture du journal, regroupement du GET, corps lu même envoyé en deux paquets, refus des corps qui ne sont pas des erreurs, limite de dix par minute). cargo build --release --locked : code 0, aucun avertissement. python3 _tableau/garde_fous.py : « garde-fous : rien à redire », code 0. python3 _tableau/test_deployer_rust.py : « tous les cas tiennent », code 0. Doc : section datée en fin de _tableau/LXC-132.md.

Ce qui n'est pas mesuré

  • La rotation du journal (passé 4 Mo) est tenue par les cas unitaires d'erreurs.rs, pas par le banc de bout en bout : la provoquer coûterait des mégaoctets pour rien.
  • L'affichage dans l'onglet Processus et le trajet d'une vraie erreur JS se mesurent au navigateur (carte de relecture t_3ec43777).

Un trou mesuré, hors de cette carte

Le service n'écoute que sur la boucle locale du 132 (127.0.0.1:8096) ; la page, elle, est servie par le serveur Python du 8080, qui relaie. serveur_processus.concerne('/api/erreurs-page') rend False (mesuré) et do_POST retombe sur recevoir_actualiser, qui répond 404 à tout chemin hors /actualiser* (lu dans serveur_actualiser.py). Sans un relais du POST en Python, l'erreur du navigateur n'arrive jamais au service : c'est une livraison à part, signalée en commentaire de la carte et confiée au profil tableau.

Collisions

  • _tableau/rust/service/src/main.rs est aussi touché par la PR #1623 (hermes/stud-1157-rust-logs, ouverte) : rebasé ici sur origin/main c5e7c4a2, aucun conflit à ce jour. La deuxième fusion devra être rebasée.
  • _tableau/LXC-132.md est aussi touché par la PR #1623 et la PR #1624 : ma section est ajoutée en fin de fichier, loin de leurs insertions, pour rester fusionnable.
## Ce que la carte livre Deux routes nouvelles sur `service-tableau` (Rust, `_tableau/rust`) : un `POST` qui reçoit les erreurs de la page et les écrit dans un journal tournant, un `GET` qui rend les 24 dernières heures pour l'onglet Processus. ## Nouvelle route : `/api/erreurs-page` (contrat pour le front) **`POST /api/erreurs-page`** — corps JSON, tel que l'envoie `front/src/lib/erreurs-navigateur.js` : ```json {"message": "TypeError: x is not a function", "pile": "…", "onglet": "/processus", "version": "abc123", "ecran": "1920x1080", "navigateur": "Mozilla/5.0"} ``` Réponses : `200 {"ok":true}` écrit ; `200 {"ok":true,"doublon":true}` si la même erreur du même client vient d'être écrite ; `400` corps illisible, message vide, ou champ reconnu qui n'est pas du texte ; `429` au onzième envoi de la minute ; `500` journal non écrit, avec la raison en clair. **`GET /api/erreurs-page`** — les 24 dernières heures, regroupées par message (clé du front : espaces comprimés, minuscules), le plus récent d'abord : ```json {"depuis_h": 24, "groupes": 2, "total_24h": 2, "erreurs": [{"message": "…", "compte": 1, "derniere": "2026-10-14T18:52:07+00:00", "il_y_a_s": 0, "pile": "…", "onglet": "…", "version": "…", "ecran": "…", "navigateur": "…"}]} ``` Le journal est `/opt/studio/journaux/erreurs-page.jsonl` (`SERVICE_JOURNAL_ERREURS` pour le déplacer), une ligne JSON par erreur, `quand` (ISO 8601 UTC) et `ts`. **Aucune clé hors des six ci-dessus n'est écrite** — donc aucun secret, et l'adresse du client (qui sert à la limite et au dédoublonnage) n'est jamais écrite. Tournant passé 4 Mo : les 10 000 dernières lignes restent, réécrites par renommage. ## Preuves La panne d'avant, mesurée : sur le binaire d'`origin/main` (c5e7c4a2), lancé : ``` POST /api/erreurs-page → HTTP/1.1 405 Method Not Allowed (« lecture seule ») GET /api/erreurs-page → HTTP/1.1 404 Not Found journal /opt/studio/journaux/ : absent ``` Le banc rejoué sur `origin/main` échoue de la même façon (`405 lecture seule`), et passe sur la branche. Sur la branche, même binaire, mêmes commandes : ``` POST {"message":"TypeError: apres", …, "jeton":"un-secret"} → 200 {"ok":true} POST (même erreur) → 200 {"ok":true,"doublon":true} POST {"message":"RangeError: autre"} → 200 {"ok":true} GET /api/erreurs-page → 200 {"depuis_h":24,"groupes":2,"total_24h":2,…} journal 2 lignes, aucune trace de « un-secret » ``` `cargo test --release --locked` (branche, commit ab165f74) : **53 cas, 0 échec, code 0**, dont les 4 nouveaux de `service/tests/erreurs_page.rs`, qui lancent le vrai binaire et lui parlent par TCP (écriture du journal, regroupement du GET, corps lu même envoyé en deux paquets, refus des corps qui ne sont pas des erreurs, limite de dix par minute). `cargo build --release --locked` : code 0, aucun avertissement. `python3 _tableau/garde_fous.py` : « garde-fous : rien à redire », code 0. `python3 _tableau/test_deployer_rust.py` : « tous les cas tiennent », code 0. Doc : section datée en fin de `_tableau/LXC-132.md`. ## Ce qui n'est pas mesuré - **La rotation du journal** (passé 4 Mo) est tenue par les cas unitaires d'`erreurs.rs`, pas par le banc de bout en bout : la provoquer coûterait des mégaoctets pour rien. - **L'affichage dans l'onglet Processus** et le trajet d'une vraie erreur JS se mesurent au navigateur (carte de relecture `t_3ec43777`). ## Un trou mesuré, hors de cette carte Le service n'écoute que sur la boucle locale du 132 (`127.0.0.1:8096`) ; la page, elle, est servie par le serveur Python du 8080, qui relaie. `serveur_processus.concerne('/api/erreurs-page')` rend **False** (mesuré) et `do_POST` retombe sur `recevoir_actualiser`, qui répond `404` à tout chemin hors `/actualiser*` (lu dans `serveur_actualiser.py`). Sans un relais du POST en Python, l'erreur du navigateur n'arrive jamais au service : c'est une livraison à part, signalée en commentaire de la carte et confiée au profil `tableau`. ## Collisions - `_tableau/rust/service/src/main.rs` est aussi touché par la PR #1623 (`hermes/stud-1157-rust-logs`, ouverte) : rebasé ici sur `origin/main` c5e7c4a2, aucun conflit à ce jour. La deuxième fusion devra être rebasée. - `_tableau/LXC-132.md` est aussi touché par la PR #1623 et la PR #1624 : ma section est ajoutée **en fin de fichier**, loin de leurs insertions, pour rester fusionnable.
service-tableau : POST et GET /api/erreurs-page, journal tournant (STUD-1157)
All checks were successful
Tests du tableau (Rust + Svelte) / Rust (_tableau/rust) (push) Successful in 16s
Tests du tableau (Rust + Svelte) / Front Svelte (_tableau/front) (push) Successful in 12s
Tests du tableau (Rust + Svelte) / Rust (_tableau/rust) (pull_request) Successful in 17s
Tests du tableau (Rust + Svelte) / Front Svelte (_tableau/front) (pull_request) Successful in 13s
ab165f749b
Cause : le 13/10 au soir, « la page est cassée » est venu de l'opérateur et non d'une mesure.
Rien dans la page ne remontait ses erreurs, et le service du 132 n'avait aucune route pour
les recevoir : sur le binaire d'alors, mesuré, un POST /api/erreurs-page rendait « 405 Method
Not Allowed » et un GET « 404 », sans rien écrire sur le disque — l'erreur du navigateur était
perdue.

Remède : les deux routes sur la même adresse. Le POST écrit une ligne par erreur dans le
journal tournant /opt/studio/journaux/erreurs-page.jsonl (dossier créé au besoin ; seuls les
six champs du front — message, pile, onglet, version, écran, navigateur — toute autre clé est
ignorée, donc aucun secret, et l'adresse du client n'est jamais écrite). Le GET rend les 24
dernières heures regroupées par message, avec compte et dernière occurrence, pour l'onglet
Processus. Limite de 10 envois par minute et par client (429 au-delà), dédoublonnage à la même
clé que le front (erreurs.js), corps borné à 64 Ko, requête lue en entier avant de répondre.
Journal tournant passé 4 Mo : les 10 000 dernières lignes restent, par renommage.

Bancs : service/tests/erreurs_page.rs lance le vrai binaire et lui parle par TCP (écriture du
journal, regroupement du GET, corps en deux paquets, refus, limite de dix par minute) ; rejoué
sur origin/main, il échoue en « 405 lecture seule », la panne d'avant. cargo test --release
--locked : 53 cas, 0 échec. cargo build --release --locked sans avertissement. garde_fous.py
et test_deployer_rust.py verts. Doc : section datée de _tableau/LXC-132.md.

Reste à part : le service n'écoute que sur la boucle locale du 132 et la page vient du serveur
Python du 8080 ; serveur_processus.py ne relayait que des GET, le relais du POST est une
livraison séparée (l'erreur du navigateur reste sur un 404 sans elle).
Collaborator

fusion-auto : pas de fusion, la PR est en conflit avec main : à rebaser. Le chef de l'atelier renvoie la carte à l'agent ; l'étiquette tombera d'elle-même une fois corrigé.

`fusion-auto` : pas de fusion, la PR est en conflit avec main : à rebaser. Le chef de l'atelier renvoie la carte à l'agent ; l'étiquette tombera d'elle-même une fois corrigé.
hermes-bot force-pushed hermes/stud-1157-backend-erreurs from ab165f749b
All checks were successful
Tests du tableau (Rust + Svelte) / Rust (_tableau/rust) (push) Successful in 16s
Tests du tableau (Rust + Svelte) / Front Svelte (_tableau/front) (push) Successful in 12s
Tests du tableau (Rust + Svelte) / Rust (_tableau/rust) (pull_request) Successful in 17s
Tests du tableau (Rust + Svelte) / Front Svelte (_tableau/front) (pull_request) Successful in 13s
to c64a1ba572
All checks were successful
Tests du tableau (Rust + Svelte) / Rust (_tableau/rust) (push) Successful in 25s
Tests du tableau (Rust + Svelte) / Front Svelte (_tableau/front) (push) Successful in 13s
Tests du tableau (Rust + Svelte) / Rust (_tableau/rust) (pull_request) Successful in 23s
Tests du tableau (Rust + Svelte) / Front Svelte (_tableau/front) (pull_request) Successful in 14s
2026-10-15 02:43:49 +02:00
Compare
Author
Collaborator

Rebasage sur main 4334b8da (carte t_b6a7239d) — conflits resolus en gardant les deux cotes.

Tete : c64a1ba5 (etait ab165f74). cargo test --release --locked : 88 cas, 0 echec (53 avant rebasage). cargo build --release --locked : code 0, aucun avertissement. python3 _tableau/garde_fous.py : « rien a redire ». CI pc-studio 4/4 verte. mergeable=true, etiquette conflit retiree.

Decisions de resolution :

  • service/src/main.rs : l'architecture de main (lecture bornee, atelier::Demande, aiguillage sur dem.methode / dem.chemin) accueille le journal et les deux routes, servies d'un bloc par erreurs::servir. Les helpers d'ecriture d'une reponse (repondre, ecrire, lecture_seule, SERVEUR) passent dans service/src/http.rs : sans eux, main.rs (591 lignes dans main) franchissait le plafond de 600 lignes du garde-fou.
  • service/src/erreurs.rs : servir, CORPS_MAX, Journal::depuis_env rejoignent le module.
  • service/src/lib.rs : modules de main (conso, replis, top, videos) plus erreurs et http.
  • _tableau/LXC-132.md : les deux sections sont gardees (le relais Python apporte par main, le service de cette branche) ; rien n'est retire de main.

Ordre des fusions (decision du chef, 2026-10-14) : #1623 devait fusionner d'abord. Mesure : main 4334b8da ne contient pas collecteur::erreurs ; la PR #1623 est elle-meme en conflit (mergeable=false), sans carte de rebasage. J'ai donc rebase sur le main courant. Consequence : #1623 devra se rebaser apres #1642, et l'homonymie collecteur::erreurs / service::erreurs sera a arbitrer la-bas — deux crates distinctes, donc aucun renommage necessaire ici (il n'y a que service::erreurs dans cette tete).

python3 _tableau/lancer-tests.py --tout : 170 bancs verts, 1 rouge (test_accueil_parite.py) et le cliquet de couverture en baisse (coeur 99,1 % < 99,4 %, ensemble 96,7 % < 99,0 %) — les deux rejoues a l'identique sur main 4334b8da (banc inchange, couverture-objectif.json identique) : pre-existants, hors de cette carte.

Rebasage sur `main` `4334b8da` (carte t_b6a7239d) — conflits resolus en gardant les deux cotes. Tete : `c64a1ba5` (etait `ab165f74`). `cargo test --release --locked` : 88 cas, 0 echec (53 avant rebasage). `cargo build --release --locked` : code 0, aucun avertissement. `python3 _tableau/garde_fous.py` : « rien a redire ». CI pc-studio 4/4 verte. `mergeable=true`, etiquette `conflit` retiree. Decisions de resolution : - `service/src/main.rs` : l'architecture de main (lecture bornee, `atelier::Demande`, aiguillage sur `dem.methode` / `dem.chemin`) accueille le journal et les deux routes, servies d'un bloc par `erreurs::servir`. Les helpers d'ecriture d'une reponse (`repondre`, `ecrire`, `lecture_seule`, `SERVEUR`) passent dans `service/src/http.rs` : sans eux, `main.rs` (591 lignes dans `main`) franchissait le plafond de 600 lignes du garde-fou. - `service/src/erreurs.rs` : `servir`, `CORPS_MAX`, `Journal::depuis_env` rejoignent le module. - `service/src/lib.rs` : modules de main (conso, replis, top, videos) plus `erreurs` et `http`. - `_tableau/LXC-132.md` : les deux sections sont gardees (le relais Python apporte par `main`, le service de cette branche) ; rien n'est retire de `main`. Ordre des fusions (decision du chef, 2026-10-14) : #1623 devait fusionner d'abord. Mesure : `main` `4334b8da` ne contient pas `collecteur::erreurs` ; la PR #1623 est elle-meme en conflit (`mergeable=false`), sans carte de rebasage. J'ai donc rebase sur le `main` courant. Consequence : #1623 devra se rebaser apres #1642, et l'homonymie `collecteur::erreurs` / `service::erreurs` sera a arbitrer la-bas — deux crates distinctes, donc aucun renommage necessaire ici (il n'y a que `service::erreurs` dans cette tete). `python3 _tableau/lancer-tests.py --tout` : 170 bancs verts, 1 rouge (`test_accueil_parite.py`) et le cliquet de couverture en baisse (coeur 99,1 % < 99,4 %, ensemble 96,7 % < 99,0 %) — les deux rejoues a l'identique sur `main` `4334b8da` (banc inchange, `couverture-objectif.json` identique) : pre-existants, hors de cette carte.
hermes-fusion deleted branch hermes/stud-1157-backend-erreurs 2026-10-15 07:50:28 +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!1642
No description provided.