Joseara
FR EN

Nouveautés de la plateforme

Version 6.14 — 189 mises à jour sur les 30 derniers jours.

  1. 6.14
    5b2193f8

    Chantier 19 bis : aucun fichier de passage d'un cabinet ne reste hors de chez lui

    Le chantier 19 effaçait tout ce qui est RANGÉ par cabinet ; des temporaires y échappaient, dont des copies de fichiers de clients (44 copies d'import de Ket et 270 résidus relevés sur le poste, effacés).

  2. 6.13
    05cfc178

    Tests propres : plus aucun test ne laisse de fichiers sur le poste

    37 178 fichiers orphelins s'étaient accumulés sur le poste de dev : des tests effaçaient les lignes de leurs cabinets d'essai, pas leurs fichiers. - ServiceSuppressionEntreprise::fichiersDuCabinet(id) : la liste de TOUS les fichiers d'un cabinet, lue en base — source unique de la purge et des tests. - tests/Support/FichiersDesCabinetsDeTest::effacer() en tête du nettoyage des 7 classes désignées (AnalyserFichierPourSaisieTool, AssistantIaFichier, KetDocumentGeneration, KetFichierClassement, KetSaisieDepuisFichier, RepriseParPaliers, ProductionIntermediaireRubrique). - Garde-fou permanent : l'…

  3. 6.12
    2076b5cf

    Chantier 19 : supprimer un cabinet efface tout ce qui est à lui, fichiers et lignes

    Décision de Serge (avant l'ouverture) : la suppression d'un cabinet ne laisse rien de lui. - SUR LE DISQUE, sept emplacements (avant : logo et pièces seulement) — fichiers joints au chat de Ket et documents qu'il a produits (retrouvés en base AVANT la purge), dépôts et exports de l'échange (<id>/), cache audio de la voix (<id>/). Chaque emplacement est déclaré UNE fois en paramètre (app.dossier_des_fichiers_de_ket, _documents_de_ket, _de_l_echange, _de_la_voix_de_ket), que lisent Vich, le code qui y écrit et la purge. - EN BASE, les tables rattachées INDIRECTEMENT (sans entreprise_id) restaie…

  4. 6.11
    3fd1d382

    Chantier 18, commit 6 : une pièce ne sort par le relevé public que si elle est partagée

    Option (c) de Serge : case « Partagée avec le client » sur la pièce (Document), DÉCOCHÉE par défaut — toutes les pièces existantes naissent non partagées (migration). - Relevé public /soa/{token} : la liste d'une police ne montre que les pièces partagées (SoaPoliceDocumentsCollector::piecesPartagees) ; le téléchargement refuse une pièce non partagée par la même réponse qu'un lien invalide (pieceServieAuClient). Le courtier, lui, voit toujours tout (collectFor). - Écran : la case dans le dialogue d'une pièce (aide + phrase dans la colonne d'explication) ; dans les listes, la mention « Partagée…

  5. 6.10
    4d655cbc

    Après la purge : identifiants de commit à jour, public/uploads/ ignoré en bloc, logos verrouillés par construction

    - L'historique a été réécrit le 2026-10-22 (33 fichiers déposés commités par le passé, dont quatre dumps de base, retirés de toutes les branches) : les identifiants de commit cités dans les skills, le README de déploiement et bin/deploy.sh sont remplacés par les nouveaux (table de correspondance de git filter-repo ; 26 références). - .gitignore : TOUT public/uploads/ est ignoré, verrous (.htaccess) et .gitkeep exceptés — un nouveau sous-dossier ne serait plus suivi. - Décision de Serge : la liste de refus du verrou des logos est un écart accepté (LiteSpeed), À CONDITION que le téléversement s…

  6. 6.09
    9c557256

    Chantier 18 : corrections de la seconde revue

    - B1 : cinq gabarits écrivaient l'adresse du logo en dur (images/entreprises/…) — relevé public et interne, aperçus de note, analyse de bordereau. Ils passent par vich_uploader_asset ; un test refuse toute adresse de logo écrite en dur. - C1-C3, app:documents:deplacer : une copie non conforme est retirée de la destination (elle ne bloque plus la relance) ; une empreinte illisible est un échec ; le rapport dit ce qui a VRAIMENT été supprimé ; les fichiers que la base ne désigne pas sont comptés et nommés, laissés en place. - C4 : un retour arrière au-delà du chantier 18 rend les pièces introuv…

  7. 6.08
    342e9606

    Chantier 18, commit 5 : règles inscrites, liste de contrôle de production

    - Skill jsbrokers-dev §4 : les fichiers déposés se servent, ne se publient jamais — app.dossier_des_pieces hors de public/, DocumentFichier::chemin(), ReponseDePiece pour toute réponse, NomAleatoire (public), tests/Support/DossierDesPieces, et l'E2E des fichiers sur une instance Apache qui LIT les .htaccess (l'instance habituelle les ignore). §8 : état du chantier 18 (reste le commit 6, case « Partagée avec le client »). - deploiement/README.md : la recette du chantier 18 (rapport du déplacement, disque, aucune URL ne sert une pièce, route contrôlée, logo, sauvegarde de var/uploads chez l'héb…

  8. 6.07
    fd0d2aa9

    Chantier 18, commit 4 : les pièces quittent la racine web, les logos ont leur dossier

    Décisions de Serge : - PIÈCES (Document) dans var/uploads/documents (app.dossier_des_pieces), HORS de public/ : aucune URL ne les atteint, seules les routes contrôlées les servent (ReponseDePiece). - LOGOS publics (montrés par <img>) mais dans public/uploads/logos (app.dossier_des_logos), séparés des images de marque suivies par git ; .htaccess : images seulement, sandbox, nosniff. Le refus du SVG au téléversement existait (chantier 13) et reste testé. - NOMS ALÉATOIRES pour les nouveaux dépôts (NomAleatoire : 128 bits + extension) ; le nom lisible reste en base. Les fichiers existants garden…

  9. 6.06
    3311e0c0

    Chantier 18, commit 3 : un fichier déposé ne s'ouvre jamais comme une page de Joseara

    Une seule réponse, ReponseDePiece, sert désormais TOUS les fichiers déposés : pièce de l'espace de travail (unitaire et archive), relevé public, et les trois routes de fichiers de Ket. Décisions de Serge : - affichage dans le navigateur seulement s'il est demandé ET si le type RÉEL (lu dans le contenu, pas l'extension) est PDF, PNG, JPEG, GIF ou WebP ; tout le reste en Content-Disposition: attachment, et jamais servi sous un type HTML, SVG ou XML ; - X-Content-Type-Options: nosniff et Content-Security-Policy: sandbox sur chaque réponse, archives ZIP comprises ; - nom d'origine nettoyé (contrô…

  10. 6.05
    67fe84a3

    Chantier 18, commit 2 : l'emplacement d'une pièce a une source unique

    Le dossier des pièces déposées est le paramètre app.dossier_des_pieces, lu par le mapping Vich et par la purge d'un cabinet ; le code n'y accède que par DocumentFichier::chemin(). Quatre chemins « public/uploads/documents » écrits en dur (bordereau : affichage et soumission de l'analyse, PDF d'analyse, commande d'enrichissement) y passent. Rien ne change encore d'emplacement : c'est ce qui permettra de déplacer le dossier hors de public/ en une ligne.

  11. 6.04
    040f7293

    Chantier 18, commit 1 : public/pdfs et sa génération de démonstration supprimés (code mort, décision de Serge)

    La route /admin/entreprise/pdf/{id} n'était appelée par aucun écran ; son gestionnaire n'écrivait qu'un « Ceci est juste un exemple » dans public/pdfs/{id}.txt — un dossier servi directement, sans .htaccess versionné. Retirés : route, gabarit, message et gestionnaire, leur routage Messenger, trois traductions, la purge de ce dossier à la suppression d'un cabinet, le test qui exigeait le dossier, et ses mentions dans bin/deploy.sh, .gitignore et le README de déploiement. Les fichiers déjà présents en production seront supprimés par Serge.

  12. 6.03
    29bc89ce

    Skill jsbrokers-dev : chantier 17 (Tâches) fait, chantier 18 (fichiers déposés hors de public/) inscrit, avant l'ouverture

    Aucun détail complémentaire n’accompagne cette mise à jour.

  13. 6.02
    38fec8ca

    Tâches : une frontière de visibilité, posée par le serveur à chaque porte (décisions de Serge)

    Un invité ne voit une tâche — et ses retours et pièces — que si son exécutant ou son auteur appartient à son cercle : lui, son responsable, ses assistants directs (un niveau). Les tâches sans exécutant restent communes ; l'administrateur du cabinet (propriétaire ou délégué) voit tout. Hors frontière : 404, jamais un 200 vide ni un refus nommé. Recalculé à chaque requête. Source unique : TacheVisibiliteScope ; lecteur : InviteCourant.

  14. 6.01
    61bfd34c

    Administrateur du cabinet = le propriétaire ou le délégué (décision de Serge)

    « Effacer les filtres » ne retire « Mon portefeuille » que pour un administrateur. Celui-ci n'est plus déduit d'un cumul de droits sur toutes les rubriques (import, validation des congés… rendaient la qualité inatteignable) : c'est le propriétaire ou le délégué « gestionnaire des invités ». Seul le propriétaire supprime le cabinet et achète des tokens.

  15. 6.00
    817bbee5

    Listes : une liste vide dit pourquoi, et propose le bon geste (chantier 6)

    Le serveur détermine la cause d'une liste vide (CauseDeListeVide) et rend l'état vide, au premier affichage comme à chaque recherche (`etatVide` de la réponse) : — « Aucune donnée » : rien ici ; — « Aucune fiche dans votre portefeuille » + « Afficher tout le cabinet », proposé à TOUS (la chip est un confort de lecture, option A confirmée par Serge) ; — « Aucune fiche ne correspond à vos filtres » + « Effacer les filtres », qui ne retire « Mon portefeuille » que pour un administrateur du cabinet (WorkspaceAccessResolver::estAdministrateurDuCabinet). Les boutons portent les clés à retirer, choi…

  16. 5.99
    336b1837

    Skill jsbrokers-dev : « Mon portefeuille » reste un confort (option A), cloisonnement entre chargés de compte en CIBLE éventuelle

    Décision de Serge du 2026-10-21. Et plus de fichier tenu hors des commits : une modification qui n'est pas la nôtre se montre, Serge décide.

  17. 5.98
    efc5a0a0

    Console : le bloc « Supervision » du tableau de bord est testé avec un défaut ouvert

    Le 2026-10-08, ce bloc (/console/dashboard/block/supervision) répondait 500 en production — et seulement là : il ne rend sa liste que lorsqu'un défaut est OUVERT, ce que la suite ne semait jamais pour lui. Le test tient désormais les deux états : sans défaut, et avec un défaut ouvert, dont le type doit apparaître dans la liste rendue.

  18. 5.97
    4fe2b93e

    Éditeur riche : Tab sort de l'éditeur, plus de piège clavier (WCAG 2.1.2)

    Quill attachait Tab à l'insertion d'une tabulation et à l'indentation des listes : au clavier, on entrait dans l'éditeur sans pouvoir en sortir. Ses raccourcis Tab sont retirés (SANS_TABULATION, texte-riche-regles.js) : Tab et Maj+Tab passent au champ suivant ou précédent, liste comprise. Pas de bouton d'indentation (décision de Serge) : la barre n'en avait pas, et le format n'est pas autorisé.

  19. 5.96
    168004d7

    Dialogues (suivi du chantier 2) : un seul gestionnaire, saisie sans geste protégée

    Bordereau : l'analyse injectée dans l'espace de travail installait un second dialog-manager — chaque ouverture créait deux dialogues identiques, donc un risque de double enregistrement. Le second reste désormais inerte (gestionnaire-dialogues.js) ; l'unification reste au chantier 3.

  20. 5.95
    4990959c

    Dialogues et messages : Échap ferme sans rien perdre, une erreur reste (chantier 2)

    Échap (règles echap-dialogue.js, un seul gestionnaire dans dialog-manager, en phase de capture, d'après la pile des modales) : ferme d'abord ce qui est ouvert dans le dialogue (autocomplétion, menu, picker, liste « +N »), puis le dialogue du dessus seulement ; rien pendant une saisie Quill, un envoi en cours (Fermer verrouillé), une touche maintenue, ni dans « Aller à la page ». Un formulaire se ferme par dialog-instance#close(), qui demande « Abandonner ? » quand l'empreinte du formulaire a changé — prise au premier geste, création comprise, Quill et fichiers compris ; la question se ferme p…

  21. 5.94
    d6fc454f

    Recherche des Tâches : plus d'e-mail après F5 (chantier 16, suite)

    La boîte de confirmation, incluse sur TOUTES les pages, portait un champ mot de passe caché. Le gestionnaire de mots de passe d'Edge/Chrome le remplissait à chaque chargement et versait l'identifiant dans le dernier champ texte qui le précède : la recherche des Tâches du tableau de bord. `autocomplete="off"` n'y peut rien, et la valeur est cachée au script jusqu'au premier geste — le filet `:autofill` ne pouvait pas l'effacer.

  22. 5.93
    d6dedf8e

    Onglets : chacun retrouve SES filtres, et personne ceux d'un autre (chantier 15)

    Routage par onglet. Une réponse lente (chargement ou rafraîchissement d'une liste) partait sous le nom de l'onglet AFFICHÉ à son arrivée : les filtres des Avenants se mémorisaient sur les Tranches, et le F5 les y rejouait (défaut 3, même cause que la fuite). Une réponse appartient désormais à l'onglet qui l'a demandée ; une recherche va à l'onglet qu'elle nomme (routage-onglet.js). Un contexte provisoire (onglet en chargement) ou un filtre restauré pas encore reposé ne se mémorise plus.

  23. 5.92
    8dbd4bd2

    Console : le remboursement d'une vente ne part jamais sans confirmation

    Décision de Serge (2026-10-20) : verrouiller si c'est important pour la sécurité des données. Ça l'est : un remboursement est irréversible — l'achat passe REFUNDED, les tokens sont retirés du compte du client, un AVOIR est émis (document intangible) et le client est notifié.

  24. 5.91
    ea1719a5

    Recherche : aucun filtre ne s'applique sans avoir été tapé (chantier 16)

    Chrome et Edge prenaient les champs de recherche anonymes pour un identifiant et y collaient l'adresse e-mail de l'utilisateur : la liste des tâches du tableau de bord se filtrait sur ce texte, à son insu (vu en production par Serge le 2026-10-20). Inventaire : 29 champs de recherche ou de filtre (28 gabarits, 1 JS), aucun entièrement protégé.

  25. 5.90
    467470e2

    Fichiers déposés : jamais exécutés sur joseara.com (chantier 13)

    Deux dossiers publics reçoivent des fichiers d'utilisateurs, servis par le serveur web — donc hors PHP et hors de la politique de sécurité de l'application. Un .html ou un .svg piégé y aurait été ouvert depuis joseara.com, ses scripts lisant la session du cabinet.

  26. 5.89
    bfba9fdb

    Icônes : les 31 nommées dans le code sont figées dans le dépôt, plus d'Iconify au rendu

    Une icône absente de assets/icons est téléchargée depuis api.iconify.design AU MOMENT DU RENDU : si Iconify ne répond pas, la page tombe en 500 (vu deux fois en test le 2026-10-19 : « Could not resolve host: api.iconify.design », lucide:users et mdi:account-arrow-right-outline). IconInvocationsVendoriseesTest ne lisait que les GABARITS ; les noms fournis par le CODE (canevas de liste et de formulaire, IconExtension, IconController) lui échappaient. Décision de Serge (2026-10-20) : figer les icônes dans Joseara.

  27. 5.88
    575eac4d

    CSP (6/6) : la politique de sécurité est APPLIQUÉE

    Le navigateur refuse désormais d'exécuter tout script que Joseara n'a pas prévu : même si une donnée piégée échappait un jour à l'échappement, elle ne s'exécuterait pas.

  28. 5.87
    6170f130

    Réseau : une lecture coupée en route est retentée une fois

    Production, 2026-10-19 : des requêtes coupées en plein vol (ERR_CONNECTION_RESET, ERR_CONNECTION_CLOSED) sur des adresses différentes à chaque chargement — un onglet restait vide, le suivi de Ket échouait. Le serveur n'avait rien refusé : la connexion était coupée. Décision de Serge (2026-10-20) : livrer la reprise.

  29. 5.86
    c6908799

    Recherche : un critère inconnu de la rubrique est écarté, plus de liste en 500

    Supervision de production (2026-10-20, 7 occurrences depuis le 19) : « Class App\Entity\Tranche has no field or association named __echeance_avenant__ ». Le chip d'échéance des Avenants était parti dans une requête sur les Tranches ; la porte « champ simple » du moteur passait le nom tel quel à Doctrine — erreur de sémantique, liste entière en 500.

  30. 5.85
    b9212447

    CSP (5/6) : les règles inscrites dans les skills

    Les garde-fous sont en place depuis les commits 1 à 4 (PolitiqueCspTest, JournalCspTest, AdresseDuNavigateurTest, GestesSansCodeTest). Ce commit écrit les règles là où un écran neuf les trouvera :

  31. 5.84
    bec197df

    CSP (4/6) : le tableau de bord sans code dans le HTML — plus aucun on…= nulle part

    Les blocs du tableau de bord appelaient les fonctions window.db… d'assets/app.js par 63 attributs onclick/oninput/oncontextmenu, et app.js fabriquait 3 lignes de production avec un onclick : tout cela serait refusé par la politique appliquée.

  32. 5.83
    919e9f3c

    CSP (3/6) : les 47 gestes génériques sans code dans le HTML

    La politique de sécurité refusera tout code écrit dans un attribut (onclick="…") : c'est ce qu'une donnée piégée y glisserait. Les gestes génériques passent par des data-action.

  33. 5.82
    84f3b602

    Dépendances JavaScript : importmap:audit à zéro

    Après le chantier 12 (Composer, 60 avis → 0), l'audit des paquets JavaScript (importmap) signalait encore 3 High, 1 Medium, 2 Low.

  34. 5.81
    6404fba8

    CSP (2/6) : plus aucune ressource d'un autre site

    La politique de sécurité n'autorise plus aucun hôte externe : tout ce que la page charge vient de joseara.com. Les pages n'attendent plus jsDelivr (2 à 5 s mesurées au poste).

  35. 5.80
    c6c8629a

    CSP (1/6) : politique en observation, nonce par requête, collecte des violations

    Dernier filet contre une faille d'échappement : le navigateur n'exécutera que nos fichiers et les <script> inline qui portent le nonce de la réponse. En Report-Only tant que les gestionnaires on…= ne sont pas convertis (commits 3-4) et que Serge n'a pas parcouru la liste de contrôle (commit 6).

  36. 5.79
    7d94c4cf

    Recherche : on cherche le texte saisi, plus le HTML de l'éditeur

    Un champ riche (24 champs, registre ChampsEnTexteRiche) est stocké en HTML. La recherche faisait son LIKE sur ce HTML : « strong » ou « <p> » trouvaient la fiche, « Relancer le client » ne la trouvait pas quand une balise coupait la phrase, « A & B » non plus (stocké &amp;), et une image collée (base64) répondait à des lettres au hasard.

  37. 5.78
    88e51aa3

    Publication : plus de « git pull » — deploy.sh se met à jour lui-même

    L'INCIDENT (2026-10-19). `publier` s'est arrêté : « Your local changes to public/.htaccess would be overwritten by merge ». L'alias faisait `git pull` avant deploy.sh ; or le .htaccess du serveur porte TOUJOURS les blocs de l'hébergeur (remis par deploy.sh à l'étape 4) — le premier commit touchant ce fichier (381e35da) a bloqué le pull. Déblocage sûr : `cd ~/joseara && bash bin/deploy.sh` (deploy.sh sauve les blocs, fetch, reset, les remet).

  38. 5.77
    381e35da

    Alertes « Untrusted Host mail.joseara.com » : la cause est traitée, plus de faux e-mails

    LA CAUSE. cPanel sert mail.joseara.com depuis le dossier du site. En production, Symfony n'accepte que joseara.com et www.joseara.com (trusted_hosts : parade à l'empoisonnement d'en-tête Host). Chaque visite de mail.joseara.com (robots, clients de messagerie) levait « Untrusted Host », journalisé en ERROR : la chaîne d'alerte l'envoyait par e-mail, et le dédoublonnage ne couvre que cinq minutes — d'où l'alerte qui revenait sans cesse.

  39. 5.76
    8dd54eb3

    Recherche : un « % » ou un « _ » tapé est du texte, plus un joker — sur TOUS les champs

    Le terme saisi entrait tel quel dans le motif du LIKE : « 100% » trouvait « 1000 », « A_B » trouvait « AxB ». Ce changement touche toutes les recherches du service, champs simples comme riches.

  40. 5.75
    0b7a1382

    Symfony 7.1 -> 7.4 LTS : plus aucun avis de sécurité sur les dépendances

    composer audit : 26 avis -> 0. Symfony 7.1 n'était plus maintenu : 24 avis n'y auraient jamais été corrigés (contournement d'autorisation par PATH_INFO, pare-feu, injection CRLF dans une adresse d'e-mail…). 7.4 est une LTS, maintenue en sécurité jusqu'en 2029. PHP 8.2 suffit (check-platform-reqs) ; hors Symfony, seul doctrine/dbal bouge (3.9 -> 3.10).

  41. 5.74
    dfcf0e63

    Erreurs : le texte d'une panne technique ne s'affiche plus, le refus du métier si

    Treize catch relayaient $e->getMessage() à l'écran. Prouvé : l'aperçu d'un bordereau dont le classeur manque affichait « File "C:\JSBrokers_1_0_3/public/uploads/documents/…" does not exist » — le chemin du serveur, chez le courtier.

  42. 5.73
    9766bb33

    Dépendances : 34 avis de sécurité corrigés sans changer de version de Symfony

    composer audit : 60 avis -> 26 (tous restants sur la branche Symfony 7.1, en fin de maintenance : chantier 12-B, montée en 7.4 LTS).

  43. 5.72
    5dcf9c34

    Échappement, fin : le localStorage relu n'est plus cru sur parole ; skills à jour

    - Icônes : le cache persistant (jsb-icon-v1::) était réinjecté en innerHTML à chaque page, sans repasser par le serveur. Une seule porte, icone-memorisee.js (cerveau et les deux circuits de bordereau-analysis) : un SVG inerte, sinon l'entrée est effacée et l'icône redemandée. Clés inchangées : le cache existant reste valable. - Onglets : loadUrl et sourceUrl relus du stockage sont fetchés puis injectés en HTML ; url-de-confiance.js n'accepte que notre origine. - Infobulle d'attribut (tooltip_controller) : textContent. Les descriptions des canevas sont du texte (vérifié : aucune balise). - Ski…

  44. 5.71
    eb93b46f

    Texte riche : assaini à l'écriture, lu comme du texte partout ailleurs

    Tout <textarea> d'un dialogue est un éditeur Quill : ces champs stockent du HTML, qui était enregistré puis réaffiché tel quel. Un <img onerror> collé ou posté s'exécutait à l'ouverture de la fiche.

  45. 5.70
    b444c215

    Reversements : corriger un versement ne perd plus sa description

    Le picker de reversement n'envoie aucune description — il n'en propose pas. Le serveur la réécrivait pourtant avec ce qu'il ne recevait pas (`$donnees['description'] ?? null`) : chaque correction d'un versement par le picker (une date, un montant) effaçait la description saisie ailleurs, sans un mot.

  46. 5.69
    2e81f5e7

    Cloisonnement : un identifiant d'autrui est introuvable, ni avalé ni nommé

    Chantier d'échappement, C5.

  47. 5.68
    5c6e6cec

    Tableau de bord, espace de travail, recherche : une donnée saisie n'y devient plus du HTML

    Chantier d'échappement, C4.

  48. 5.67
    13105281

    Déploiement : les dépendances se comparent à vendor/, plus à l'historique git

    Incident du 2026-10-17 : le déploiement de 6a2c0802 a échoué au cache:warmup (« RateLimiter component is not installed ») et le site est resté en maintenance.

  49. 5.66
    6a2c0802

    Formulaire de contact : ni relais d'e-mails, ni porte ouverte aux robots

    Chantier d'échappement, C3. Un visiteur sans compte choisit l'adresse où Joseara envoie l'accusé de réception : sans garde, le formulaire relayait sous notre signature le texte de son choix, à qui il voulait, autant de fois qu'il voulait.

  50. 5.65
    d6a81192

    Toasts et confirmations : un texte reste du texte, une seule fonction d'échappement

    Chantier d'échappement, C2.

  51. 5.64
    19aa92cd

    E-mails et pages du serveur : une donnée saisie n'y devient plus du HTML

    Chantier d'échappement, C1.

  52. 5.63
    0a85d97f

    Console : un sujet de ticket ou un nom de cabinet ne s'exécute plus chez l'agent

    XSS stockée, du dehors vers la console Joseara — correctif d'urgence.

  53. 5.62
    8af5f1ae

    Skill jsbrokers-dev : deux valeurs en dur de plus au chantier 5

    - `color:#0d2440` hors charte, en style inline, sur 11 titres et libellés du picker de facturation (_facturation_picker.html.twig). - Format de date `d/m/Y` écrit en dur sur la carte de piste (_carte_piste.html.twig:40), au lieu de format_datetime.

  54. 5.61
    9b419b7d

    Skill jsbrokers-dev : huit chantiers de développement inscrits, sans code

    Décisions de Serge du 2026-10-16, sur l'inventaire fait pour jsb-construire-rubrique :

  55. 5.60
    76a37fa7

    Skill jsb-construire-rubrique : construire une rubrique, du cadrage à la livraison (lot 1)

    Une skill qui dit dans quel ordre travailler et va chercher la règle au bon moment, sans répéter jsbrokers-dev, courtage-assurance, reglementation-rdc-arca, ergonomie-web ni charte-couleurs.

  56. 5.59
    c5c6aebe

    Skills : corrections après relecture

    - Les trois en-têtes perdent `trigger when` (clé non standard) : les mots-clés de déclenchement passent dans `description`. - courtage-assurance §2 : le règlement d'une note n'a pas d'outil Ket dédié, mais il est couvert — `preparer_operations` crée le Paiement (CouvertureDesEcrans, motif écrit). « Aucun outil Ket pour l'encaissement d'une note » contredisait le manifeste. - jsbrokers-dev §4 : tout contenu dynamique est échappé (Twig par défaut, textContent en JS, jamais |raw ni innerHTML sur une donnée saisie, infobulles comprises). Incident : les infobulles du tableau de bord (300ed88a). Le…

  57. 5.58
    6dd79dfb

    Skill réglementaire : homologation DGI des factures, chantier décidé

    La DGI permet de raccorder le module de facturation à sa plateforme pour homologuer chaque facture (QR code, références fiscales). Décision de Serge du 2026-10-16 : intégration de l'API DGI, chantier ultérieur. Il remplace la question « facture normalisée : à confirmer ».

  58. 5.57
    ffa05505

    Conservation : l'écriture du ZIP devient testable, et l'échec de la fermeture est prouvé

    Le correctif « archive vide = remise échouée » (2011ff8b) n'avait pas de test : il fallait faire disparaître un fichier pendant la fermeture du ZIP.

  59. 5.56
    2011ff8b

    Conservation : la moindre pièce comptable exige l'archive, justificatifs compris

    Décisions de Serge du 2026-10-16 : un cabinet qui porte la moindre pièce comptable ne se supprime pas sans archive comptable préalable, remise au cabinet (export téléchargeable).

  60. 5.55
    e4cf510f

    Notes : app:notes:figer dit ce qu'elle compare ; avoir multi-échéances inscrit

    - app:notes:figer distingue désormais deux chiffres. Le CONTRÔLE (figé − recalculé juste avant le figeage) doit valoir 0,00 (✓) ; un écart (⚠) bloque la confirmation. Le RESTE À ENCAISSER (montant − paiements) est une information : une note partiellement réglée se fige telle quelle. À blanc, le figeage se fait en mémoire et n'est pas écrit, si bien que le contrôle se lit avant de confirmer. - courtage-assurance §7 point 7 : l'avoir sur une police à plusieurs échéances, chantier connu (écart mesuré au niveau du revenu), avec sa requête de mesure en lecture seule à relancer régulièrement. Rien…

  61. 5.54
    850abbce

    Skills : règle OHADA des notes acquise (numéro, intangibilité, conservation)

    courtage-assurance §5 : trois invariants acquis — numérotation continue attribuée à la validation (remplace celle du 2026-10-14), intangibilité d'une note validée (montants figés, avoir seule correction, écart à facturer / à créditer, note de reprise supprimable entière), conservation dix ans (archive avant toute purge). La règle « note réglée » vise désormais les brouillons et les notes de reprise. La mention « en attente du comptable » sur la numérotation est retirée ; le chantier 6 est fait.

  62. 5.53
    b0878a28

    Notes : les pièces se conservent dix ans ; archive avant toute purge

    Règle OHADA (Acte uniforme relatif au droit comptable), décision de Serge du 2026-10-15 : rien ne purge une note émise. La suppression d'un cabinet entier n'est permise qu'APRÈS la remise de son archive comptable, à jour.

  63. 5.52
    c98e2749

    Notes : une note validée est intangible ; l'écart se facture ou se crédite

    Règle OHADA, décision de Serge du 2026-10-15 : une note validée ne se modifie plus et ne se supprime pas. Toute correction passe par la note contraire (avoir), puis par une nouvelle note si besoin.

  64. 5.51
    378d3a9c

    Notes : les montants se figent à la validation (règle OHADA)

    Le montant d'une note n'était stocké nulle part : il se recalculait à chaque lecture, et une prime, un taux ou un chargement corrigés après coup changeaient une facture déjà envoyée — son PDF, son solde, son écriture au journal. Décision de Serge du 2026-10-15 : une note validée est intangible.

  65. 5.50
    f7b164c3

    Notes : le numéro définitif naît à la validation (règle OHADA)

    Pratique comptable OHADA (SYSCOHADA révisé), décision de Serge du 2026-10-15 : chaque note validée porte un numéro unique, chronologique et continu dans sa série (ND-/NC-AAAA-NNNNN, par cabinet, année d'émission et type), attribué au moment où la validation fait naître la créance.

  66. 5.49
    307077eb

    Commission : l'assiette est la somme des lignes du chargement cible

    Une cotation peut porter plusieurs lignes du même chargement (deux « prime nette ») : l'écran ne comptait que la première, Ket les additionnait déjà. La commission porte désormais sur leur somme, partout (10 000 + 4 000 à 15 % : 2 100, et non 1 500).

  67. 5.48
    c4712f33

    Commission : un type neuf s'adosse au taux du risque

    Le formulaire d'un nouveau type de commission s'ouvrait sur 10 % ET le drapeau « taux du risque ». Le pourcentage du type passant avant le risque (TarifDuRevenu), le drapeau restait sans effet tant que les 10 % demeuraient. Décision du 2026-10-15 : le type neuf s'ouvre sans pourcentage, drapeau coché, et facture le taux du risque ; le courtier qui veut un taux fixe le saisit.

  68. 5.47
    b5dd6277

    Commission : une seule règle de tarif, l'ordre des écrans fait foi

    TarifDuRevenu devient la source unique du tarif d'une commission, dans l'ordre des écrans et de la facturation : taux du revenu, forfait du revenu, pourcentage du type, forfait du type, puis taux du risque si le type s'y adosse. Les écrans, la description du calcul, l'annonce de Ket et la colonne de tarif de l'export du portefeuille la lisent tous.

  69. 5.46
    545f5633

    Sinistres : le sélecteur des modèles de pièces ne montre que le cabinet

    Règle posée par Serge le 2026-10-15 : un sélecteur n'affiche JAMAIS les données d'un autre cabinet. La nature d'une pièce de sinistre se choisissait parmi les modèles de pièces de TOUS les cabinets (noms et descriptions) ; l'écriture refusait déjà un modèle étranger, la liste non.

  70. 5.45
    5c6b2e3e

    Commission : une taxe ne sert jamais d'assiette, et le chargement cible reste du cabinet

    Chantier « Assiette et source unique de la commission », étape 1 (écart 1 ; décision du 2026-10-15). L'Art. 2 du barème ARCA exprime les taux sur la prime nette, hors impôts et taxes ; un type de revenu pouvait pourtant viser la TVA ou l'ARCA.

  71. 5.44
    361ea4cf

    Skills : Art. 2 en lecture étroite, chantier prioritaire sur l'assiette de la commission

    Décisions de Serge du 2026-10-15. - reglementation-rdc-arca : la base de la commission est la prime nette seule (hors fronting, frais accessoires et taxes), pratique du marché ; le réglage par défaut est conforme — à confirmer auprès de l'ARCA en cas de contrôle. - courtage-assurance : chantier PRIORITAIRE « Assiette et source unique de la commission » en tête des chantiers (invariant « une source unique par montant ») : taxe interdite comme chargement cible, une seule règle de priorité (l'ordre des écrans fait foi), commission sur la somme des lignes du chargement cible ; historique à tranch…

  72. 5.43
    e6445f50

    Skill réglementaire : assiette de la commission (Art. 2) et chantiers ARCA

    Vérification en lecture seule, rien corrigé.

  73. 5.42
    17333f69

    Skill réglementaire : barème ARCA 005/24 en référence, constat des 43 risques semés

    - references/bareme-arca-005-24.md : transcription du Règlement n° 005/24 (taux minima et maxima Vie et IARD, règles d'application), fournie par Serge ; à relire contre le texte officiel avant tout usage dans le code. - §6 : le barème est référencé ; il n'est pas implémenté (seuls les maxima sont semés, sans minima, contrôle de fourchette ni régimes des Art. 3 à 6). - Constat, sans correction : les 43 taux de risques_defaut.json égalent un à un les maxima du barème de 2024 (aucun hors fourchette, correspondance 1 pour 1) ; aucun indice d'un barème antérieur, sans pouvoir exclure des valeurs c…

  74. 5.41
    63544886

    Skill courtage-assurance : trois chantiers ultérieurs, numérotation à confirmer

    - Chantiers ultérieurs signalés le 2026-10-15 (non décidés) : badge « Mon portefeuille » incomplet ; trois chemins de documents manquants sous « Mon portefeuille » (55 jointures sur un plafond de 61) ; plan Ket en deux temps refusé à l'analyse. - À confirmer : numérotation des notes sans trou (Serge consulte son comptable) — ne rien modifier avant sa réponse.

  75. 5.40
    1a926f6c

    Notes : la page de démonstration /admin/note/test est supprimée

    Elle ne servait qu'à elle-même : la route admin.note.test, son gabarit components/note/editor.html.twig et le contrôleur Stimulus invoice_editor, que rien d'autre n'utilisait. Elle portait un sélecteur de monnaie CDF/USD factice, contraire à la monnaie de travail unique.

  76. 5.39
    ba02347c

    Monnaies : une seule monnaie de travail par cabinet, aucun montant converti

    Décisions du 2026-10-14 et du 2026-10-15. La prémisse « convertir l'existant » est tombée : aucun montant ne porte sa monnaie, et chaque formulaire affichait la monnaie d'affichage à côté du champ pendant la saisie — l'existant y est donc déjà. Rien n'est converti.

  77. 5.38
    8d6f97f1

    Mon portefeuille : ce qui descend d'une piste suit son responsable

    Décision du 2026-10-14. Cotations, polices, tranches, paiements de prime, tâches, retours et documents rattachés à une piste suivent désormais le RESPONSABLE de la piste (ResponsableDePiste : gestionnaire du portefeuille du client, sinon créateur de la piste), comme la piste elle-même. Avant, une piste montée pour un client sans portefeuille était dans « Mon portefeuille » de son créateur, sans sa cotation ni sa police. Ce qui ne dépend que du CLIENT (client, sinistres, document du client) garde la règle du gestionnaire. La règle ne fait qu'ajouter : personne ne perd ce qu'il voyait.

  78. 5.37
    8e30dd39

    Constante : 325 méthodes mortes supprimées ; Ket ouvre le PDF de la note

    Décisions du 2026-10-14. Le dernier grep a démenti la prémisse du nettoyage : la chaîne getIdPoste() n'était pas seulement morte, elle servait l'ancien état TCPDF (EtatsController), prouvé en 500 pour tout destinataire (Article::getMontant() et getIdPoste() n'existent plus), et l'export « note_pdf » / « bordereau_pdf » de Ket y menait.

  79. 5.36
    59c96204

    Notes : un numéro unique dans le cabinet, et chronologique

    Décisions du 2026-10-14. La référence d'une note était 'N' . time() : ni ordre d'émission, ni unicité, aucun contrôle.

  80. 5.35
    a49664f7

    Notes : une note réglée ne se supprime pas et ne perd pas de ligne

    Décisions du 2026-10-14. Une note qui a reçu au moins un paiement est une pièce comptable acquise : elle s'annule par la note contraire (une note de débit par une note de crédit, et inversement), jamais par effacement.

  81. 5.34
    7295a96c

    Skills métier : les réponses du 2026-10-14 intégrées

    - Numérotation des notes : référence générée par le produit, unique et chronologique par cabinet, champ éditable (unicité contrôlée). - Monnaie unique : l'existant saisi dans une autre monnaie sera converti dans la monnaie d'affichage. - Branche VIE : ARCA 2 % confirmé, pas de TVA — des défauts, éditables par cabinet. - Principe : le produit définit des comportements PAR DÉFAUT, jamais des valeurs imposées.

  82. 5.33
    9678aa25

    Skills métier : courtage-assurance et reglementation-rdc-arca

    courtage-assurance : glossaire terme → entité, cycle de vie piste → police → facturation → encaissement → rétrocession, tableau type de mouvement → dates → chemin → prime, invariants métier et comptables avec preuves (fichier:ligne) et tests ; invariants CIBLES décidés le 2026-10-14 (numérotation des notes — prioritaire —, monnaie unique, « Mon portefeuille » étendu, note réglée non supprimable) avec état actuel et écart ; chantiers décidés.

  83. 5.32
    05536e7b

    Skill jsbrokers-dev : les règles de développement du dépôt

    BIC Cristal, cloisonnement entre cabinets (AppartenanceAuCabinet, 404 sans nommer), source unique et parité écran ↔ Ket, « le serveur écrit, le navigateur clone », procédure de test (PHPUnit dossier par dossier, une suite à la fois, mocksess, node, E2E), livraison et mode Plan. Règle d'usage : tout plan qui touche le métier consulte d'abord courtage-assurance (et reglementation-rdc-arca) et cite l'invariant qu'il préserve.

  84. 5.31
    945860be

    Listes : la dernière demande fait autorité, pas la dernière réponse

    Deux rafraîchissements du même onglet partaient en parallèle et s'affichaient dans l'ordre d'ARRIVÉE. Rejeu bridé (CPU ×6, Slow 3G) de Liste → Cartes → Liste → Cartes à 200 ms : la vue finissait en Liste alors que le dernier clic demandait Cartes (2 rejeux sur 3).

  85. 5.30
    97a9c2a0

    Cookies : une seule façon de les écrire et de les lire

    controllers/cookies.js : cookieAEcrire (valeur encodée, tout le site, un an, SameSite=Lax) et lireCookie (décodée ; REPLI sur le préfixe « 9111986 » qu'ajoutait l'ancien saveCookie). La vue Cartes s'y appuie au lieu de son propre code.

  86. 5.29
    ad5ddadf

    Ancien tableau de bord : la page autonome est retirée

    L'action `index` d'EntrepriseDashbordController (page à formulaire de dates, JSBTableauDeBordBuilder) n'était plus servie par aucun lien et répondait 500 ; l'espace de travail et ses blocs la remplacent. Retirés : l'action, le constructeur de tableau, CriteresRechercheDashBordDTO, RechercheDashBordType, templates/admin/dashbord/** et le menu segments/menu_entreprise_dashbord (inclus nulle part). La route répond désormais 404 ; les tests de bascule de cabinet le constatent, et vérifient toujours que rien n'est écrit.

  87. 5.28
    93f949d6

    Vue Cartes : la Σ des Transformées se calcule par paquets, et s'arrête au plafond

    La colonne additionnait la commission de TOUTES les polices souscrites du filtre, par getIndicateursGlobaux — qui calcule aussi tout le reste. Mesuré sur 1 000 polices : ≈ 7,0 s la réponse de la vue Cartes.

  88. 5.27
    f6401ad6

    Pistes : « Mon portefeuille » = les pistes dont je suis le responsable, partout pareil

    Le responsable d'une piste : le gestionnaire du portefeuille de son client, sinon son créateur. La carte le disait ; la liste, Ket et la vigie ne retenaient que le gestionnaire — une piste montée pour un client sans portefeuille portait le nom de son créateur sur sa carte et disparaissait de « Mon portefeuille » de ce même créateur.

  89. 5.26
    2c12a757

    Avenants : un seul chemin par type — le mouvement de la police adopte la piste dérivée

    Renouvellement, prorogation, annulation, résiliation : la piste dérivée et sa proposition, montées et négociées à part, ne se doublent plus. La carte du pipe (« Renouveler », « Proroger », « Annuler la police », « Résilier la police »), le bouton de ligne des cotations et Ket ouvrent le MOUVEMENT de la police de base, qui les ADOPTE :

  90. 5.25
    998a72a0

    Avenants : une souscription sans prime n'a pas de sens, et le serveur le garantit

    Le premier avenant d'une cotation exige une prime chiffrée quand le type de la piste crée, reconduit ou étend la garantie (souscription, prorogation, renouvellement). L'incorporation, l'annulation et la résiliation en sont exemptées ; un avenant suivant reste toujours permis. Une table, une garde (DefautsDeSouscription), pour tous les chemins :

  91. 5.24
    77dde0be

    Note : la création par le dialogue ne tombe plus en 422 « Référence obligatoire »

    Créer une note depuis son dialogue échouait à chaque fois. La référence, « Générée automatiquement », est un champ DÉSACTIVÉ : il n'est jamais soumis. La colonne est NOT NULL, et ControllerUtilsTrait::handleFormSubmission contrôlait les champs obligatoires AVANT le beforePersist qui posait la référence. Le défaut précède le chantier de la vue Cartes : il a été reproduit à l'identique au commit d67fbd91 (worktree temporaire).

  92. 5.23
    ce72199e

    Pistes : « Voir les transformées » et « Voir dans la liste » disent où ils mènent

    Deux liens qui mènent à la vue Liste portent désormais l’icône de la bascule « Liste » (action:vue-liste), devant leur libellé. Au repos : un lien cobalt au soulignement fin, cible de 44 px. Au survol : une pastille --bg-cobalt-subtle, le texte en --cobalt-dark, l'icône qui avance de 2 px ; anneau de focus cobalt au clavier ; aucun mouvement sous prefers-reduced-motion. Jetons de la charte uniquement. Dans la colonne terminale, le lien se centre sur l'axe du texte qu'il suit.

  93. 5.22
    300ed88a

    Pistes et collections : ce qui est enregistré se voit, et le pipe se lit d'un survol

    Dix retours d'usage sur la vue Cartes et les collections, chacun diagnostiqué avant correction.

  94. 5.21
    2efcce3c

    Pistes : la vue Cartes — le pipe commercial en colonnes, avec la prochaine action

    La liste principale des Pistes s'ouvre désormais sur une vue Cartes (bascule « Vue : Cartes | Liste ») qui répond à une seule question : où en est chaque piste, et quelle est la prochaine action ?

  95. 5.20
    2809442f

    Pistes : quatre étapes du pipe, un chip qui les montre, et un avenant souscrit pareil partout

    - Les étapes, déduites des cotations (aucune n'est stockée) : À coter → En cotation → Offre chiffrée → Transformée ; « En cours » réunit les trois premières. Source unique : PisteTransformationScope (ETAPES, etapeDe, un seuil de prime chiffrée — Σ chargements ≥ 0,005, soit ROUND(Σ, 2) > 0, que DQL ne sait pas écrire). - SQL : JSBDynamicSearchService::predicatsDEtapePiste() (T souscrite, C prime chiffrée, K au moins une cotation), en EXISTS corrélés ; le chip les combine. - PHP : indicateurs etapePipe / etapePipeLibelle / etapePipeNiveau de chaque ligne. - Chip « Statut » : À coter · En cotati…

  96. 5.19
    62d7ebde

    Vue Liste : sept irrégularités corrigées, dont deux chips qui se vidaient en silence

    - Chips « En cours » (Pistes) et « En attente » (Cotations) : le filtre était un `NOT IN (SELECT IDENTITY(...) FROM Avenant …)` borné à aucun cabinet. Une police sans cotation ou une cotation sans piste, n'importe où sur la plateforme, y mettait un NULL et vidait les deux chips dans TOUS les cabinets. Réécrits en EXISTS corrélés ; une cotation sans piste non souscrite redevient « en attente », comme le dit sa fiche. - Premier rendu de la liste : `isPrincipalTab` testait un préfixe qu'aucun gabarit ne produit — l'annonce initiale était du code mort, et la sélection ne revenait pas après F5 (co…

  97. 5.18
    21b5defc

    Un identifiant venu de la requête ne désigne plus rien hors du cabinet ouvert

    mayAccessEntity() ne juge que le TYPE d'entité ; aucun SQLFilter ni Voter ne bornait les find() au cabinet. Cinq formes d'un même défaut restaient ouvertes :

  98. 5.17
    d67fbd91

    Facturer la commission : dire ce qui reste à encaisser, et sur quelle note

    Une commission entièrement portée par une note mais réglée en partie (11,60 facturés, 8,00 encaissés) était annoncée « 3,60 à collecter » par la liste, la fiche et Ket, tandis que la fenêtre de facturation répondait « Rien à facturer », sans un mot du reste dû. Elle avait raison sur le fond : émettre une seconde note serait une double facturation. Mais elle taisait la créance et n'offrait aucune suite.

  99. 5.16
    39eb2689

    Clôturer sans avoir une échéance sans rien à créditer, et tous les lecteurs prouvés

    - Nouvelle voie de régularisation. Une échéance « à régulariser » sur laquelle rien n'a été facturé n'avait aucune issue : l'avoir n'a rien à créditer. « Clôturer sans avoir » (avec confirmation) la fait passer « Régularisée », sans note ; « Rouvrir la régularisation » revient en arrière, et l'abandon du mouvement restitue l'état d'avant comme pour le reste. Clôture refusée (409) dès qu'une note de commission ou un avoir existe. - Indicateur regularisationVoie (avoir | cloture | avoir_emis | cloturee) : l'action « Régulariser par note de crédit » n'est offerte que si une commission a été fact…

  100. 5.15
    2e4a1416

    Trois défauts d'interface relevés au contrôle dans le navigateur

    - Boîte de mouvement : l'aperçu initial (date par défaut) et celui de la date saisie partaient presque ensemble ; si le premier répondait en dernier, il recouvrait le second et l'aperçu ne disait plus ce que le champ allait écrire. Seule la dernière demande s'affiche désormais. - Barre d'outils : initialize() passe deux fois (Stimulus, puis connect()) et posait deux écouteurs app:context.changed, dont disconnect() n'ôtait que le second. Le survivant touchait une barre détruite (TypeError « reading 'afficher' »). Une seule fonction liée. - Fenêtre de facturation en note de crédit : elle parlai…

  101. 5.14
    d0bd5efd

    Déploiement : le rattrapage des échéances n'est plus que simulé

    bin/deploy.sh ne lance plus app:echeances:regulariser en mode réel. Après les migrations, il joue seulement --rattrapage --dry-run, en affiche le récapitulatif (police, échéance, prime, acte en cause) et donne la commande à lancer pour appliquer. Le mode réel se lance à la main, après lecture. En répétition à blanc (migrations non jouées), la simulation est seulement annoncée. Un échec de la simulation est signalé sans interrompre le déploiement.

  102. 5.13
    22019065

    Régulariser une échéance sans objet, et rattraper les résiliations déjà enregistrées

    - Actions sur une échéance « à régulariser » (barre, clic droit, volet) : « Régulariser par note de crédit » ouvre la fenêtre de facturation en type crédit, sur ce qui a déjà été facturé — une fois l'avoir émis, l'échéance se lit « Régularisée » ; « Déclarer due quand même » la remet dans le recouvrement (prime acquise à l'assureur), réversible par « Remettre à régulariser ». Gestes refusés (409) s'ils ne correspondent plus à l'état réel. - Fenêtre de facturation : paramètre type=credit, transmis au rechargement et à l'envoi. Corrige au passage la perte des échéances au changement de destinat…

  103. 5.12
    3b3b090d

    Une échéance « à régulariser » sort du recouvrement, partout, et reste visible sur sa fiche

    Un seul point d'application : TrancheIndicatorStrategy. Ses montants ne changent pas, mais ce qu'on en réclame tombe à zéro (solde de prime, solde de commission, commission et rétro exigibles) ; le statut devient « À régulariser » (« Régularisée » une fois la note de crédit émise), l'urgence un badge neutre, et la fiche explique pourquoi et quoi faire — avec la commission déjà facturée, nommée.

  104. 5.11
    25640638

    Une annulation ou une résiliation met « à régulariser » les échéances qu'elle rend sans objet

    Après une résiliation en cours de période, le recouvrement continuait de réclamer la prime de l'année entière. Modèle et règle (les lecteurs suivent dans le commit suivant) :

  105. 5.10
    ee382a97

    Un sinistre bloque l'abandon d'un mouvement, et la boîte de mouvement tient sur téléphone

    - Abandon d'un mouvement (règle unique LiensProteges::refusDeSuppression, écran et Ket) : refusé aussi quand l'avenant qui en est issu porte un sinistre — même référence de police, survenu pendant sa période. Un sinistre doit toujours porter une police existante. Un sinistre de la police de base, sur sa propre période, ne bloque rien. - Boîte de mouvement : le libellé du champ date est visible, au jeton de la charte des titres de champ (.field-label, #343a40, contraste ≈ 11:1). - Socle des boîtes : sous 576 px, le pied passe à la ligne — l'aide sur toute la largeur, les boutons dessous. Sur u…

  106. 5.09
    4287672b

    Tableau de bord : le portefeuille en vigueur et la production de l'exercice ne se confondent plus

    Les totaux ne lisent plus le statut de renouvellement pour dire une date : une police échue jamais renouvelée restait comptée à vie, et une police renouvelée s'additionnait à son successeur.

  107. 5.08
    883a81bb

    Abandonner un mouvement n'efface jamais de l'argent, et la boîte de mouvement gagne en lisibilité

    - Règle unique LiensProteges::refusDeSuppression() : supprimer l'opportunité dérivée d'un mouvement est refusé, avec un message qui nomme l'avenant et les écritures, dès qu'un avenant qui en est issu porte un encaissement de prime, une note émise ou un encaissement de note. Sinon l'abandon est permis, même pour un renouvellement abouti. Appliquée par SuppressionEnCascade::planifier() (annonce et exécution, écran et Ket), et vérifiée AVANT toute dissociation à l'écran (409) et dans l'abandon de Ket, pour qu'un refus ne laisse aucun lien coupé en mémoire. Ket et l'écran disent désormais la même…

  108. 5.07
    d693d8a6

    Un renouvellement ne crée plus d'avenant né expiré, et le statut de la police suit ses mouvements

    Le signalement « un avenant renouvelé reste Échu » : la police de base sortait bien des échus, mais son successeur, calculé au lendemain d'une échéance vieille de 18 mois, naissait lui-même expiré et y entrait à son tour.

  109. 5.06
    1854d26e

    Une conversation prend le titre de sa première vraie question

    « CONV#78 » cède la place, dès l'envoi de la première vraie question, à un titre qui s'en inspire — et l'utilisateur peut toujours le renommer ensuite. Les deux griefs qui avaient fait abandonner l'ancien titre (80 premiers caractères, une phrase entière dans l'onglet) sont tenus : le titre est débarrassé de ses formules de politesse et tient en 40 caractères, « … » compris.

  110. 5.05
    423df1cb

    Ket accueille une conversation vide par un bonjour, et ne déroule plus le programme du jour

    Chaque nouveau fil s'ouvrait sur le programme du jour complet — jusqu'à sept tableaux avant même la première question. Une conversation vide s'ouvre désormais sur un accueil bref, à la manière des assistants grand public : « Bonjour, Serge » (« Bonsoir » de 18 h à 4 h 59, dans le fuseau APP_TIMEZONE nommé explicitement), une phrase tirée au hasard, et jusqu'à trois suggestions qui PRÉ-REMPLISSENT le champ sans rien envoyer ni écraser un brouillon.

  111. 5.04
    c776334a

    Le contrôle du .htaccess ne confond plus une panne d'outil avec une différence

    LE CORRECTIF DE LA VEILLE A REFUSÉ À TORT. Il comparait le fichier sans blocs à celui du dépôt par « diff » sur deux substitutions de processus. Celles-ci passent par /dev/fd, ABSENT sous CloudLinux (CageFS isole chaque compte) : diff a échoué (« /dev/fd/63: No such file or directory »), et son échec a été lu comme une différence — « modifié HORS des blocs de l'hébergeur », alors que le fichier ne l'était pas.

  112. 5.03
    ec685542

    Le déploiement garde les blocs que cPanel écrit dans .htaccess, et refuse un PHP trop ancien

    LE 2026-10-08, « publier » S'EST ARRÊTÉ NET : cPanel avait ajouté son bloc de gestionnaire PHP dans public/.htaccess, fichier versionné, et le garde-fou « fichier suivi modifié sur le serveur » refusait tout. Le bloc disait bien plus grave : il imposait PHP 8.1 au SITE, quand l'application exige 8.2 — ce que le contrôle du PHP de la ligne de commande (8.2.28) ne pouvait pas voir.

  113. 5.02
    3e48c996

    La pastille d'un onglet du relevé paraît dès l'ouverture de la fiche

    Le nombre de mouvements d'un onglet Prime, Commission, Rétrocommissions ou Taxes ne s'affichait qu'après un clic sur l'onglet : la pastille arrivait avec la liste. Trop tard — elle doit dire ce que la fiche contient avant qu'on aille voir.

  114. 5.01
    823ba8d7

    Un excédent se nomme « Trop-versé » ou « Trop-perçu », et le rafraîchissement du relevé est prouvé

    UN SOLDE NÉGATIF SE LIT EN MOTS. « Solde -60,00 » demandait de savoir que le signe moins voulait dire un excédent. La synthèse NOMME désormais ce qui a été payé en trop, montant en positif : « Trop-perçu » quand le cabinet ou l'assureur a reçu plus que dû (prime, commission), « Trop-versé » quand c'est le cabinet qui a trop payé (rétrocessions, taxes).

  115. 5.00
    a9e548fb

    La fiche d'une tranche montre sa prime, sa commission, ses rétrocessions et ses taxes

    LE GESTIONNAIRE VOIT TOUT, SANS RIEN TOUCHER. La fiche Tranche ne portait que Principal, Paiements de prime et Documents. Elle gagne quatre onglets en lecture seule — Prime, Commission, Rétrocommissions, Taxes — chacun une synthèse (dû, exigible, payé, solde) et la liste des mouvements, total au pied. « Paiements de prime » est fondu dans « Prime » : les signalements y sont des lignes, à côté des factures client et des bordereaux.

  116. 4.99
    8abaf13d

    Un dialogue ne propose plus que les gestes que le serveur accepte

    LES BOUTONS SUIVENT LES DROITS. « Ajouter », « Modifier », « Supprimer » d'une collection, comme « Facturer la commission » ou « Signaler un paiement de prime », s'affichaient à tous : seul le serveur refusait, au clic. Un gestionnaire de compte, qui doit tout voir sans toucher à la comptabilité, se voyait offrir des gestes interdits.

  117. 4.98
    f711dd90

    Le formulaire d'une fiche perd ses gouttières, et le menu contextuel sa plomberie en double

    LE FORMULAIRE PREND LA GRAMMAIRE DU WORKSPACE. La colonne du formulaire gardait une marge, un cadre gris arrondi autour des onglets, et des cartes de champ séparées par seize pixels de vide — quand les lignes d'une liste du workspace se touchent et ne se séparent que par un filet. La colonne n'a plus de marge ; l'entête « Fiche client », l'alerte et les intertitres deviennent des bandeaux pleine largeur ; le cadre des onglets disparaît ; les cartes de champ deviennent jointives, séparées par un filet d'un pixel, sans ombre ni coins arrondis. Les formulaires de rôles suivent.

  118. 4.97
    9dfbd1eb

    Une action ne se défait plus à l'« Enregistrer » suivant, et le titre nomme la fiche

    « Retirer du portefeuille », lancé depuis la fiche d'un client, s'appliquait en base — mais le dialogue gardait l'ancien portefeuille dans son formulaire, et l'« Enregistrer » suivant le réécrivait. Le retrait était défait sans un mot. Aucune action ne prévenait le dialogue qu'elle venait de changer la fiche qu'il affiche, et le serveur acceptait de réécrire une fiche sans savoir ce qu'elle était devenue depuis son ouverture.

  119. 4.96
    49bd2220

    Le dialogue d'une fiche prend les gouttières du workspace

    La barre d'actions du dialogue était une carte blanche posée sur un fond gris, au-dessus de deux autres cartes — la colonne des attributs et le formulaire —, chacune séparée de ses voisines par seize pixels de gris. Le workspace, lui, ne pose pas de cartes : ses colonnes se touchent, et ses bandeaux (titre, onglets, barre d'outils) sont blancs, avec une gouttière de huit pixels et un filet sous eux. Le même logiciel parlait deux langues selon qu'on regardait une liste ou une fiche.

  120. 4.95
    e71f2f46

    Les actions d'une fiche ont leur barre, pleine largeur, celle du workspace

    Dans le dialogue d'une entité, les actions de la fiche vivaient dans une barre sombre maison, coincée en haut de la colonne des attributs calculés : quatre cents pixels pour neuf boutons, dont le dernier sortait du cadre. Elle disparaissait avec la colonne quand la fiche n'avait aucun attribut calculé, ne regroupait aucune famille, et ne ressemblait en rien à la barre du workspace qui propose pourtant LES MÊMES actions.

  121. 4.94
    e7968eac

    Un sinistre ne porte plus que sur une police réellement souscrite

    La référence de police d'un sinistre était un champ de texte libre : on pouvait y écrire n'importe quoi, et rien ne le relevait jamais. Un dossier finissait rattaché à une police inexistante — on s'en apercevait en réclamant à l'assureur, quand il était trop tard pour corriger la saisie.

  122. 4.93
    f5b9c886

    Les pistes et les sinistres d'un client se lisent et se créent depuis sa fiche

    La fiche d'un client montrait ses contacts et ses documents, mais ni ses pistes ni ses sinistres. Pour voir les affaires qu'on lui avait ouvertes, il fallait quitter sa fiche, changer de rubrique, et l'y rechercher — celui-là même qu'on venait de quitter. Deux onglets de plus, et une entrée « Créer un sinistre » au clic droit de la rubrique, suppriment ce détour.

  123. 4.92
    6260de2a

    La collection d'un autre cabinet cesse d'être lisible, et un onglet hors périmètre disparaît

    Deux trous d'accès sur le même chemin, trouvés en écrivant le banc des onglets de la fiche client.

  124. 4.91
    d7ae4c47

    Le mouvement réduit neutralise enfin les cinq squelettes de chargement

    La seule règle `prefers-reduced-motion` du projet ne couvrait que `.jsb-onglet` : le shimmer des squelettes tournait malgré la préférence du système, sur les cinq squelettes existants comme sur celui du total qui vient de naître (WCAG 2.3.3).

  125. 4.90
    b332e5c7

    Le total d'une collection se lit au pied dès la création, et un squelette couvre son calcul

    On saisissait quatre chargements de 1 000 / 100 / 160 / 20 sans jamais voir 1 280 : le pied de total n'apparaissait qu'une fois la fiche parente enregistrée. La règle était délibérée — le serveur ne connaît pas les lignes qui attendent dans le tampon du navigateur, et un total qui ment est pire qu'un total absent. On ne lève pas la règle, on lève sa cause.

  126. 4.89
    72fe8259

    La requête de la liste de collection cesse d'être perdue par quarante-quatre contrôleurs

    `handleCollectionApiRequest()` accepte une `Request` depuis toujours, mais un seul de ses quarante-cinq appelants la renseignait — ConditionPartageController. Partout ailleurs elle valait `null`, et `?page=` comme `?ids=` étaient lus sur un objet absent puis ignorés EN SILENCE : une pagination qui ne paginait pas, un rattachement invisible tant que la fiche parente n'était pas enregistrée.

  127. 4.88
    2af87bc5

    Un compte n'a qu'une seule invitation par cabinet

    Tout le cloisonnement repose sur `CabinetActif`, qui résout l'invité par `findOneBy(['utilisateur', 'entreprise'])`. Avec deux lignes, Doctrine en rend UNE, arbitrairement — selon l'ordre physique, le plan d'exécution, le cache.

  128. 4.87
    66e2c7b9

    Une entité d'un autre cabinet n'est plus lisible, ni modifiable, ni supprimable

    Le produit ne vérifiait que le TYPE. `mayAccessEntity($entityClass, …)` juge si le périmètre de rôles couvre « les Assureurs » ; il ne dit rien de l'assureur #34615. L'instance, elle, était chargée par `->find($id)` — un identifiant venu de l'URL ou du corps de la requête.

  129. 4.86
    24f71d88

    Les dix derniers champs de relation rejoignent le rendu commun

    Dix FormTypes répétaient le même `<div><strong>…</strong><div style="color: #6c757d; font-size: 0.85em; padding-left: 2px; margin-top: 2px;">…</div></div>` — un style inline hors charte, copié dix fois, et dix occasions de diverger.

  130. 4.85
    94c3ca6e

    Un champ de relation renseigné affiche enfin le nom, et rien d'autre

    Le champ « Assureur » occupait sept à dix-huit lignes une fois rempli : le nom, puis `Email: N/A | Tél: N/A`, puis cinq tuiles chiffrées empilées — prime, commission, deux taxes, rétro. Elles restaient là en permanence, alors que le choix était fait.

  131. 4.84
    21da7728

    On n'ouvre pas le cabinet d'un autre, et une page de consultation n'ouvre rien du tout

    Deux chemins écrivaient `Utilisateur::$connectedTo`, inégalement gardés, et tous deux persistaient aussitôt. C'est la clé de voûte : `setFiltreEntreprise()` et tout ce qui lit le gardien suivent cette colonne. Qui l'écrit décide de ce que l'utilisateur voit.

  132. 4.83
    8f6dc50e

    Le contrat des événements voit enfin les émetteurs qui reçoivent le nom en paramètre

    Ce test ne connaissait que deux façons d'émettre : `broadcast('app:…')` et `new CustomEvent('app:…')`. Il en manquait une troisième — une aide qui construit l'événement à partir d'un de ses paramètres :

  133. 4.82
    3f213788

    Les 48 fichiers de tests JavaScript ont enfin un point d'entrée

    Ils n'en avaient aucun. Aucune occurrence de `node --test` dans le dépôt, et `node` n'existe pas sur le serveur de déploiement : `bin/deploy.sh` ne pouvait pas les lancer. Cinq cent cinquante-trois tests écrits, jamais rejoués.

  134. 4.81
    a17bd027

    Un cabinet n'est ouvert que si l'on y a encore une invitation

    Tout le cloisonnement du produit repose sur `Utilisateur::$connectedTo`. Cette colonne était lue partout et vérifiée nulle part : personne ne s'assurait qu'une `Invite` existait encore pour le couple (utilisateur courant, cabinet ouvert).

  135. 4.80
    9f3d5bed

    Le filtre d'autocomplétion suit le cabinet OUVERT, et non ceux où l'on a un accès

    Le test de cloisonnement opposait deux comptes étrangers l'un à l'autre. Un filtre qui se tromperait de QUESTION — « à quels cabinets cet utilisateur a-t-il accès ? » au lieu de « quel cabinet est ouvert ? » — y passait au vert, puisque l'attaquant n'a aucun accès au cabinet voisin. Les deux lectures ne divergent que sur un compte qui appartient aux deux cabinets.

  136. 4.79
    1c49ba01

    Deux endpoints d'autocomplétion ne servent plus les données des autres cabinets

    Sur les vingt champs portant #[AsEntityAutocompleteField], DIX-HUIT scopaient par FormListenerFactory::setFiltreEntreprise(). Les deux autres fuyaient, et aucun des deux n'était employé par le moindre formulaire : l'attribut suffit à inscrire un champ au registre, et EntityAutocompleteController sert /autocomplete/{alias} PAR ALIAS, sans jamais regarder si un formulaire s'en sert.

  137. 4.78
    6d5b7db8

    Une collection se lit enfin d'un coup d'œil

    Une rangée affichait un titre entre guillemets, un montant en gras noyé au milieu des métadonnées, et un total qui flottait dans l'entête sans jamais désigner ce qu'il additionnait. Rien n'était faux ; rien ne se lisait.

  138. 4.77
    b9dd0c5e

    Le client d'une piste ne se redemande plus quand on le connaît déjà

    « Créer une piste » part d'un clic droit SUR un client : le geste l'a nommé, et l'entête du dialogue le rappelle. Le formulaire le redemandait pourtant, carte déployée avec les chiffres du client et une croix pour l'effacer — il proposait de défaire ce qu'on venait de faire.

  139. 4.76
    bfa099f3

    Le bandeau des onglets ne laisse plus défiler le contenu à côté de lui

    En défilant, le haut d'une carte — ou la barre d'outils de l'éditeur riche — apparaissait au-dessus de la barre des onglets, qui semblait alors chevaucher ce qu'elle était censée cacher.

  140. 4.75
    016095ce

    Chaque collection d'une fiche devient un onglet

    Un dialogue empilait ses champs puis ses collections, chacune repliée derrière un accordéon : la fiche Invité en enchaînait sept, et lançait sept requêtes pour n'en regarder qu'une. Désormais « Principal » porte les champs ordinaires, et chaque collection a son onglet — la grammaire des deux barres du workspace, le même composant, le même repli « + N ».

  141. 4.74
    923dbb73

    Les onglets d'une rubrique ressemblent enfin à ceux du workspace

    Le workspace avait deux barres d'onglets et deux grammaires pour les dessiner. Celle des rubriques ouvertes : des onglets encadrés, coins hauts arrondis, posés sur un bandeau gris, l'actif en blanc coiffé d'un liseré cobalt. Celle d'une rubrique — Principal, Contacts, Pistes, Sinistres… : des onglets soulignés, sur fond blanc, sans bandeau, dans une autre taille de police et d'icône.

  142. 4.73
    927e00db

    Une note issue d'un bordereau se reconnaît dans la liste

    Rien ne la distinguait d'une note composée à la main : mêmes montants, même statut, même ligne. Or les deux ne se corrigent pas de la même façon — l'une se reprend dans son bordereau, l'autre ligne à ligne. Il fallait ouvrir la note pour savoir d'où elle venait.

  143. 4.72
    3334dcd4

    Le compte où encaisser ne s'ouvre plus vide

    Le formulaire de paiement exige un compte bancaire. Il le préremplissait depuis la note — mais seulement si la note en portait un. Une note composée à la main, ou issue d'un bordereau, n'en porte aucun : le champ s'ouvrait vide, et l'enregistrement échouait sur « Ce champ est obligatoire » au terme d'une saisie déjà faite.

  144. 4.71
    9406706f

    Filtrer les notes par état de règlement, d'un clic

    Pour savoir ce qui restait à encaisser, il fallait lire la colonne « Statut » ligne à ligne. Sept rubriques ont une pilule de chips ; Notes n'en avait aucune. Elle en a une : Impayées · Partielles · Réglées · Sans montant · Toutes, et elle s'ouvre sur les impayées.

  145. 4.70
    8c4ae6d0

    Signaler le règlement d'une note, là où on la regarde

    Émettre une note n'est que la moitié du geste : elle part pour être PAYÉE. Or l'encaissement ne se saisissait qu'en ouvrant la note et en descendant dans l'accordéon « Paiements liés » — deux détours, et seulement si l'on y pensait. Rien ne le proposait ni depuis la fenêtre qui vient d'émettre la note, ni depuis la rubrique où on la relit trois semaines plus tard.

  146. 4.69
    912b574b

    Ouvrir une piste au client qu'on a sous les yeux

    Décider d'ouvrir une affaire à un client depuis sa rubrique obligeait à changer de rubrique, à créer une piste à blanc, puis à y rechercher ce même client à l'autocomplétion. On ressaisissait ce qu'on venait de quitter.

  147. 4.68
    98796be5

    Un onglet contextuel ne montre plus que les enfants de son parent

    L'onglet « Pistes » d'un client affichait les pistes de TOUT LE CABINET. Ses notes, ses sinistres et ses partenaires associés aussi. Pas au premier affichage — c'est ce qui a rendu le défaut invisible si longtemps — mais dès la page 2, une recherche, un « Réinitialiser » ou un rafraîchissement après enregistrement.

  148. 4.67
    ec32a63c

    La commission facturée entre en comptabilité, et le règlement éteint la créance

    Émettre une note ne produisait RIEN. Pas une écriture, pas un produit, pas une créance — il n'existait même aucun compte où la loger : l'actif du bilan ne comptait que la trésorerie et la TVA récupérable. Une commission réclamée à un assureur n'apparaissait donc ni au journal, ni au grand livre, ni au bilan. Le cabinet ne pouvait pas lire ce qu'on lui devait.

  149. 4.66
    b4af61a9

    Facturer une part de la commission, et finir la fenêtre qui la réclame

    La fenêtre de facturation était le calque de celle du reversement, mais elle n'en avait repris que la moitié : ses boutons partaient sans icône, ses champs sans pastille, et son montant n'était pas modifiable. Or on ne réclame pas toujours tout le dû — un assureur n'en reconnaît parfois qu'une part, ou un acompte a été convenu.

  150. 4.65
    1330013e

    Facturer une commission depuis l'écran, jusqu'au PDF — et cesser de la facturer deux fois

    L'assistant préparait la note ET ses lignes en un seul plan. L'écran, lui, n'ouvrait qu'un dialogue prérempli de l'EN-TÊTE : le courtier obtenait une note vide dont il composait les lignes une à une, dans un dialogue enfant, après avoir enregistré le parent. La parité jouait à l'envers.

  151. 4.64
    8438a83e

    Ket facture la commission qu'elle réclame chaque jour, et nomme ce qu'elle ne sait pas faire

    Sa boussole porte la chaîne « prime payée → commission exigible → facturation en lot (note de débit) → recouvrement ». Son programme du jour ouvre une section « commissions exigibles » commentée « il est temps de facturer l'assureur ». Et quand un courtier a demandé le plan correspondant, elle a répondu qu'elle ne trouvait « aucune tranche de commission associée à cette police » — alors que l'écran affichait « Prime payée, commission due · Commission exigible — 11,60 USD ».

  152. 4.63
    bef6c905

    Le dialogue de facturation cesse de lister le portefeuille des autres cabinets

    Sur les vingt champs d'autocomplétion du projet, dix-sept filtraient depuis toujours par `FormListenerFactory::setFiltreEntreprise()`. Deux ne le faisaient pas, et ce sont exactement les deux qu'on ouvre pour composer une ligne de facture : le REVENU à facturer et la TRANCHE de prime correspondante. Leur `query_builder` était nu — `createQueryBuilder('r')`, `createQueryBuilder('t')`, sans la moindre clause WHERE.

  153. 4.62
    ea45ed31

    Ket cesse de faire attendre devant deux modèles libres

    Le courtier lisait dans le chat : « Mon moteur a atteint sa limite de débit pour la minute en cours. Relancez-la dans 21 secondes. » Au même instant, la console des fournisseurs affichait les trois modèles à 100 % de fenêtre libre et concluait « Peut répondre maintenant ». Les deux écrans disaient vrai. Aucun ne décrivait la situation.

  154. 4.61
    d51843a8

    La console cesse de dire « prêt » quand Ket ne peut pas répondre

    Un agent lisait « gemini · prêt · minute 100 % » pendant que Ket répondait au courtier « limite de débit pour la minute en cours, relancez dans 47 secondes ». Les deux écrans disaient vrai ; aucun ne disait la même chose, et rien ne faisait le lien.

  155. 4.60
    4963042d

    La mesure cessait de mesurer quand le quota coupait la parole à Ket

    La première passe complète a rendu 25,7 %. Le chiffre était faux, et de beaucoup : sur 232 messages, 46 s'étaient terminés en « budget atteint », la boucle arrêtée faute de débit disponible sur la minute, avant même que les outils soient appelés. Le bilan les comptait en « outil attendu absent ». Il reprochait à Ket la vitesse du rejeu.

  156. 4.59
    288c7c7c

    La passe complète tient la distance, et cesse de compter mes pseudonymes

    Deux défauts du harnais, découverts en tentant enfin la passe que le plan réclamait depuis le début.

  157. 4.58
    cb8fcb71

    La console cessait de dire vrai sur les trousses de Ket

    L'écran des réglages de Ket annonçait la porte de sortie de la trousse minimale comme déclarée en « Lecture, Écriture ». Elle ne l'est dans ni l'une ni l'autre. Et il comptait ses 417 octets dans le poids des deux trousses — sur un écran dont tout l'intérêt est d'annoncer à l'administrateur ce que la plateforme envoie vraiment, et ce qu'il économise en coupant un outil.

  158. 4.57
    b0e7926e

    La mesure de justesse imprime sa marge, et invalide mes propres conclusions

    Sur deux jours, la même famille de vingt cas a rendu 57,1 %, puis 38,9 %, puis 47,1 %, puis 46,7 %. J'ai lu ces écarts comme des effets de mes changements. J'ai même annulé un lot sur cette base.

  159. 4.56
    fe64d1ba

    Le rejeu cesse de poser les questions hors de leur conversation

    « Dans cela, affiche uniquement celles dont les primes sont échues. » Rejouée dans une conversation vide, cette question ne désigne rien. Ket demandait une clarification — elle avait raison — et la mesure comptait un mauvais choix d'outil. On mesurait sa patience, pas son jugement.

  160. 4.55
    c5f86e65

    Le départage des impayés est annulé : la mesure ne l'a pas validé

    Règle du chantier : un paquet qui fait baisser le choix d'outil est ANNULÉ, pas arbitré. Elle s'applique ici, à ma propre correction.

  161. 4.54
    d9ea1d31

    Une description qui recommande un autre outil le fait gagner : on inverse le sens

    Le rejeu du corpus a mesuré ce qu'aucun test ne voit. Sur les questions de classement, le lot précédent a fait passer le bon choix d'outil de 71,4 % à 86,7 %. Sur les impayés, il l'a fait TOMBER de 57,1 % à 38,9 %.

  162. 4.53
    031a30d2

    Un « merci » ne transporte plus soixante-quatre kilo-octets d'outils

    Un message sur trois n'appelle aucun outil. Beaucoup ne sont qu'un « ok », un « merci », un « très bien » — et ils emportaient malgré tout les 64 Ko de déclarations de la trousse de lecture, pour une réponse d'une phrase.

  163. 4.52
    717b1829

    Ket cesse de transporter à chaque message ce qui ne lui sert qu'après

    Les descriptions d'outils mélangeaient trois choses : à quelle question l'outil répond, ce que son résultat contient champ par champ, et comment lire ce résultat. Seule la première aide à CHOISIR. Les deux autres ne servent qu'après l'appel — le modèle a le résultat sous les yeux quand il rédige — et partaient pourtant à chaque message, appel ou non.

  164. 4.51
    0222cb92

    Les outils de Ket portent enfin des noms qu'elle n'écorche plus

    Quatre outils changent de nom. Aucun octet gagné — ce lot vise l'autre défaut : Ket appelle un outil qui n'existe pas dans 5,3 % des cas, et chaque nom écorché coûte un aller-retour complet pour rien.

  165. 4.50
    542be5d9

    La mesure cesse de reprocher au nommage ce que la compréhension a refusé

    Le rejeu du corpus annonçait « 40 % de bons choix d'outil » sur les questions d'impayés. Le chiffre était faux, et il accusait la mauvaise pièce.

  166. 4.49
    6bfa7474

    « Combien de clients ? » et « la liste des clients » n'ont plus qu'un outil

    Ket disposait de deux outils pour la même question. Compter et lister demandaient au serveur exactement la même chose — mêmes droits, même périmètre, mêmes filtres, même requête — et seule la taille de page les distinguait. Leurs deux routages étaient d'ailleurs identiques à trois lignes près.

  167. 4.48
    fda84f68

    Ket cesse de décrire trois fois le même filtre, et d'en oublier un morceau

    Les trois outils de liste — rechercher_entites, compter_entites et ouvrir_rubrique — expliquaient au modèle les mêmes filtres, chacun dans ses propres mots. Trois textes pour une seule règle, et ils avaient déjà divergé :

  168. 4.47
    e71b13ac

    Les questions déjà posées à Ket deviennent le juge de ses prochains outils

    On savait dire ce que Ket coûte. On ne savait pas dire si elle choisit le bon outil — et sans ce chiffre, raccourcir une description reviendrait à dégrader son jugement sans le voir.

  169. 4.46
    a9bbc3eb

    Quand Ket se trompe de nom d'outil, on le sait enfin — et en production

    Ket appelle parfois un outil qui n'existe pas : « analyser_portefeuille » pour « analyse_portefeuille », « consultar_guide » en espagnol. Un filet rattrape ces écorchures depuis hier, et il laissait une trace — mais sur le mauvais canal. En production, ce canal n'écrit que les erreurs : la ligne n'était jamais enregistrée. En développement, elle se noyait dans un journal de près de quatre gigaoctets. La seule mesure du rattrapage était donc indisponible partout où le rattrapage sert.

  170. 4.45
    3f20cf6a

    Chaque phase de Ket peut avoir son modèle, et donc sa fenêtre de quota

    Les trois phases d'un message partageaient un seul modèle, donc un seul compteur de 250 000 jetons par minute — et trois messages suffisaient à le saturer. C'est la cause directe des « moteur saturé » que l'utilisateur voit. Or Google tient sa fenêtre PAR MODÈLE : une phase posée sur le sien cesse de disputer son débit aux autres.

  171. 4.44
    6cb18bb9

    La compréhension de Ket cesse de tomber quand son modèle est débordé

    Quatre messages sur dix partaient sans que personne ait compris la demande, et la cause n'était pas dans la phase : elle en était ABSENTE. Le moteur bascule depuis toujours sur un modèle de secours au premier 503 et continue de répondre ; la phase de compréhension, elle, n'avait aucune chaîne — elle échouait, simplement.

  172. 4.43
    007ce898

    Un nom d'outil écorché ne coûte plus un tour entier à Ket

    Mesuré sur les journaux au 2026-09-25 : 10 appels d'outil sur 188 — 5,3 % — visaient un nom qui n'existe pas, et TOUS étaient des quasi-homonymes du vrai. `analyser_portefeuille` pour `analyse_portefeuille` (quatre fois), `rechercher_entite` au singulier, `consultar_guide` en espagnol le temps d'un appel. Chacun rendait « introuvable », et le modèle devait repartir pour un tour de quarante mille jetons d'entrée — sur un palier gratuit où trois messages par minute saturent déjà le quota.

  173. 4.42
    9223a6ff

    Ket cesse d'armer sa propre trousse d'écriture en parlant

    Le filet lexical qui décide de la trousse relisait les TROIS DERNIERS MESSAGES DU FIL, tous rôles confondus — donc les réponses de Ket. Or le prompt lui ORDONNE de parler d'enregistrer, de modifier, d'ouvrir un formulaire : sans cela elle répondrait « je ne peux pas », ce qui est faux. Elle armait donc l'écriture toute seule, en se relisant, et le gardait trois tours. Un filet fait pour lire une intention d'UTILISATEUR se lisait lui-même.

  174. 4.41
    df8616f4

    Le rapport de jetons cesse de conclure avant de mesurer, et dit enfin pourquoi Ket se replie

    Trois angles morts fermés dans l'instrumentation, avant de toucher à ce qu'elle mesure.

  175. 4.40
    c7a1aecc

    Ket écoute la phrase jusqu'au bout : un souffle repris ne fait plus deux questions

    En mode Live, une phrase dite en deux souffles partait en deux questions, et Ket répondait au premier bout. Sur Chrome et Edge de bureau, la reconnaissance tient sa session ouverte et rend un résultat définitif à CHAQUE pause de diction : le code ne recousait les morceaux que si la session s'était refermée toute seule — la signature d'Android, qui n'arrive jamais sur un ordinateur. Le tampon de recouture existait donc depuis le début, désarmé précisément là où il fallait.

  176. 4.39
    5fe05592

    Ket cesse de nier un paiement que l'écran affiche : la date du règlement voyage avec la tranche

    Un courtier demande quel jour son client a réglé sa prime, et combien de jours se sont écoulés depuis. L'écran affiche la tranche en « Prime payée, commission due » ; le signalement — 102 $, réglés le 20/09/2026 — figure noir sur blanc dans son formulaire d'édition. Ket répond qu'aucune date n'est associée à ce règlement, puis conseille d'aller vérifier la saisie.

  177. 4.38
    56db6ee7

    Le bandeau cesse de nommer un modèle qui n'a jamais répondu

    Vérification sur trois échanges RÉELS en dev — pas sur un objet fabriqué à la main — de ce que les coulisses affichent. Deux constats, dont un seul était un défaut.

  178. 4.37
    784f812c

    Ket ouvre ses coulisses : qui a répondu, avec quels outils, en combien de temps

    Le bandeau sous la bulle de Ket annonçait « 35 714 jetons IA » et rien d'autre. Un chiffre qu'on subit : ni ce qui l'a produit, ni ce qu'il a servi à faire. Le moteur, lui, savait déjà tout — modèle qui a répondu, outils appelés, ventilation entrée / sortie / cache — mais n'en disait rien à personne hors du journal d'exploitation.

  179. 4.36
    af677040

    La console nomme le modèle qui répond vraiment, et Ket se tait quand elle n'a rien à rappeler

    DEUX MENSONGES DU MÊME GENRE : dire quelque chose plutôt que rien, là où rien était la seule réponse juste.

  180. 4.35
    148845b4

    Les deux rubriques de Ket n'en font plus qu'une, et l'écran cesse de perdre l'utilisateur en route

    « Réglages de Ket » et « Fournisseurs de Ket » étaient deux entrées voisines du même menu. Un agent qui cherchait pourquoi Ket répond mal devait deviner laquelle ouvrir — et la réponse dépendait de la cause, qu'il ignorait justement. Qui répond POUR Ket est un réglage comme les autres : c'est un onglet de « Configuration de Ket ».

  181. 4.34
    ee2d326c

    Les réglages de Ket tiennent dans un écran, et un filtre annonce qu'il travaille

    CINQ BLOCS EMPILÉS FAISAIENT UNE PAGE DE CINQ MILLE PIXELS. L'historique, tout en bas, avait toutes les chances de n'être jamais consulté — et c'est précisément lui qu'on ouvre quand on se demande « pourquoi Ket ne le fait plus ». Ils deviennent des onglets, avec le compte en pastille : on voit d'un coup d'œil qu'il y a 52 outils, 4 seuils, 41 règles et 2 changements.

  182. 4.33
    72ec316c

    Les outils de Ket se coupent depuis la console, ses seuils se règlent, et ses règles portent enfin un numéro

    TROIS LOTS EN UN, parce qu'ils ne valent que pris ensemble : un interrupteur sans journal ne se défait pas, un seuil sans borne ne se corrige pas, et une règle sans identifiant ne se cite pas.

  183. 4.32
    bf0f40e8

    Chaque outil de Ket porte sa pastille, et un alias muet ne passe plus

    SUR CINQUANTE-DEUX LIGNES, C'EST L'ICÔNE QUE L'ŒIL ATTRAPE AVANT LE NOM. La liste n'en avait aucune : on lisait cinquante-deux libellés alignés, sans repère pour retrouver du regard celui qu'on cherchait.

  184. 4.31
    cf1fbd0e

    La console montre enfin ce que Ket sait faire, et ce que chaque outil coûte

    CE QUE PERSONNE NE POUVAIT VOIR. Cinquante-deux outils partent au fournisseur à chaque échange, et leur liste n'existait nulle part ailleurs que dans src/Ai/Tool. Le support répond pourtant tous les jours à « Ket sait-elle faire X ? », et le commercial construit son argumentaire sur la réponse : aller la chercher dans le code n'est pas un chemin praticable pour eux.

  185. 4.30
    7fd1b5f8

    Un agent ne peut plus se faire super-administrateur, et un compte sans département cesse d'avoir tous les droits

    QUATRE TROUS DE DROITS, DONT DEUX MENAIENT À LA RACINE.

  186. 4.29
    c06128a1

    Une bascule de secours se compte, et un message ne peut plus durer trois minutes

    L'ÉTAPE A avait borné un APPEL à 45 secondes. Elle n'avait borné ni le MESSAGE, ni notre capacité à voir ce qui s'était passé pendant.

  187. 4.28
    8ca0f999

    On cesse de payer un outil qui ne peut que refuser, et les trois outils de liste nomment enfin le bon paramètre

    UN PARAMÈTRE QUI N'EXISTE PAS. rechercher_entites, compter_entites et ouvrir_rubrique — les trois outils les plus appelés — annonçaient au modèle un paramètre « statutPaiement » pour filtrer les tranches. Il s'appelle « axes ». Le modèle qui suivait la description émettait donc un argument ignoré en silence, et la liste rendue ne coïncidait plus avec les chips de la rubrique : précisément la parité que ces descriptions promettent. Rien ne pouvait le voir — le schéma est valide, l'appel part, l'outil répond. Seul le rapprochement entre la prose et le schéma le révèle, et c'est désormais un tes…

  188. 4.27
    c593ab6a

    Une police ne peut plus finir avant d'avoir commencé, et les règles de combinaison valent aussi pour Ket

    DEUX TROUS, ET LE SECOND EST LE PLUS LARGE.

  189. 4.26
    d5e3a3c8

    « commission » n'arme plus la trousse d'écriture

    Le filet lexical qui décide de la trousse n'avait aucune frontière de mot : il lisait un verbe d'action À L'INTÉRIEUR d'un mot du métier. « mission » se trouvait dans COMMISSION — le mot le plus fréquent du courtage —, « édit » dans CRÉDIT, « change » dans ÉCHANGE, « traite » dans TRAITEMENT, « accord » dans ACCORDÉE et « marque » dans REMARQUE. Comme le filet s'applique aux TROIS derniers messages, un seul « commission » contaminait trois tours.