Commit Graph
106 Commits
Author SHA1 Message Date
Spark 1a39d601de fix: barre d'apps mobile — CSS commune v0.1.2 et rail contextuel (BUG-118, #215)
CI / lint (push) Successful in 2m51s
CI / security (push) Successful in 1m33s
CI / test (push) Successful in 4m58s
CI / build (push) Successful in 1m27s
CI / e2e (push) Successful in 18m3s
2026-10-21 11:36:35 -04:00
bruno 411667fd88 feat: menu contextuel Déplacer/Dupliquer sidebar + réparation drag & drop interne #201 #BUG-117
CI / lint (push) Successful in 3m13s
CI / security (push) Successful in 1m59s
CI / test (push) Successful in 5m16s
CI / build (push) Successful in 1m52s
CI / e2e (push) Successful in 18m2s
2026-10-15 10:02:48 -04:00
bruno ed9029d760 fix: éditeur Forge — textarea qui ne grandit pas après insertion programmatique (tableau/code) #BUG-116
CI / lint (push) Successful in 3m17s
CI / security (push) Successful in 2m0s
CI / test (push) Successful in 5m14s
CI / build (push) Successful in 1m49s
CI / e2e (push) Successful in 17m57s
2026-10-14 22:09:28 -04:00
bruno 1892062d88 fix: éditeur Forge — espace checkbox/texte aperçu, flash du preview, menus table/langue coupés #BUG-115
CI / lint (push) Successful in 3m11s
CI / security (push) Successful in 2m0s
CI / test (push) Successful in 5m16s
CI / build (push) Successful in 1m49s
CI / e2e (push) Successful in 17m47s
2026-10-14 21:56:37 -04:00
bruno cbe3d9bc75 fix: popup currentPath is not defined après suppression/renommage de répertoire #BUG-114
CI / lint (push) Successful in 3m9s
CI / security (push) Successful in 1m59s
CI / test (push) Successful in 5m12s
CI / build (push) Successful in 1m49s
CI / e2e (push) Successful in 17m57s
2026-10-14 21:20:08 -04:00
bruno 2ebfe74459 perf: suppression de répertoire incrémentale au lieu du re-scan complet #BUG-113
CI / lint (push) Successful in 3m9s
CI / security (push) Successful in 1m55s
CI / test (push) Successful in 5m25s
CI / build (push) Successful in 1m48s
CI / e2e (push) Successful in 17m56s
2026-10-14 16:56:56 -04:00
bruno f783394f09 feat: intégration TikTak #197-200 + scoped tokens, webhooks filtrés, listes mtime/size ; fix e2e-server BUG-112
CI / lint (push) Successful in 3m17s
CI / security (push) Failing after 1m51s
CI / test (push) Successful in 5m14s
CI / build (push) Successful in 1m50s
CI / e2e (push) Successful in 18m18s
2026-10-14 11:42:53 -04:00
bruno fd192df036 fix: admin — icône fermeture modale utilisateurs + sections du dashboard affichées une à la fois BUG-111
CI / lint (push) Successful in 2m54s
CI / security (push) Successful in 1m41s
CI / test (push) Successful in 4m36s
CI / build (push) Successful in 1m34s
CI / e2e (push) Successful in 17m56s
2026-10-10 17:17:14 -04:00
bruno 8662d23ec8 fix: un dossier perso n'est plus visible par les autres comptes #194
CI / lint (push) Successful in 2m57s
CI / security (push) Successful in 1m40s
CI / test (push) Successful in 4m39s
CI / build (push) Successful in 1m34s
CI / e2e (push) Successful in 17m44s
L'admin (vaults: ["*"]) voyait le home de chaque utilisateur dans sa
barre latérale : "*" ouvrait tous les vaults, home-* compris.

- backend/auth/middleware.py : check_vault_access exige un octroi
  explicite pour tout vault home-* (nouveau is_home_vault()).
- Filtres « * » en dur remplacés par check_vault_access : dashboard,
  conflits, liens retour, favoris, abonnements push.
- /api/search : search_vaults(is_allowed=…) filtre les bruts avant
  pagination (total et page restent justes).
- backend/user_home.py : _grant n'écarte plus les comptes « * » —
  l'admin reçoit son propre home-admin (auto-réparé au démarrage).
- Tests : test_user_home.py +2, assertion API inversée dans
  test_auth_api.py (admin ne voit plus home-alice).
2026-10-10 16:42:00 -04:00
bruno 10453d8dfe feat: dossier perso (#194) — vaults home-* en tête de l'arborescence, icône maison, compose de test
CI / lint (push) Successful in 3m1s
CI / security (push) Successful in 1m41s
CI / test (push) Successful in 4m37s
CI / build (push) Successful in 1m34s
CI / e2e (push) Successful in 17m40s
- frontend/js/sidebar.js : tri stable _homeFirst appliqué à la source des
  deux listes de vaults (loadVaults + soft refresh) → les vaults home-<user>
  passent en premier, arborescence et sélecteurs cohérents.
- frontend/js/viewer.js : getVaultIcon renvoie l'icône lucide "home" pour
  home-* (même safeCreateIcons / stroke currentColor que les autres).
- docker-compose.test-win.yml : montage test_home:/vaults/Home +
  OBSIGATE_HOME_ROOT=/vaults/Home pour tester la feature en local ;
  test_home/ ajouté au .gitignore.
- Tests : sidebar-filters.test.mjs +2 (icône maison, gemme violette
  inchangée), vérifié live sur l'instance 2020 (ordre + svg.lucide-home).
2026-10-10 16:09:59 -04:00
bruno 8235d632b8 feat: dossier personnel par utilisateur — vault home-<user> + registre de vaults persistant #194
CI / lint (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / security (push) Canceled after 0s
CI / build (push) Canceled after 0s
CI / e2e (push) Canceled after 0s
- backend/user_home.py : ensure_user_home()/release_user_home() idempotents
  (mkdir, vault, watcher, octroi dans user.vaults), rappelés à la création
  d'un compte et au démarrage (migration + réparation + sweep des vaults
  home-* orphelins), dossier conservé à la suppression.
- backend/indexer.py : data/vaults.json, registre persistant des vaults
  ajoutés à la volée, fusionné par load_vault_config() — ils disparaissaient
  au premier reindex complet et au redémarrage. reload_single_vault remet
  vault_config[name] après remove_vault_from_index.
- backend/auth/router.py + routers/vaults.py : appels ensure/release +
  persistance à l'ajout/retrait d'un vault.
- docker-compose.yml : montage unique /NFS/OBSIDIAN_DOC/Home:/vaults/Home +
  OBSIGATE_HOME_ROOT (absente = fonctionnalité inactive).
- Tests : tests/test_user_home.py (12) + tests/test_auth_api.py::TestUserHome (2).
2026-10-10 00:40:35 -04:00
bruno f4c8504c8d feat: chat — les posts affichent le markdown rendu comme un document, code coloré #193
CI / lint (push) Successful in 2m50s
CI / security (push) Successful in 1m37s
CI / test (push) Successful in 4m34s
CI / build (push) Successful in 1m31s
CI / e2e (push) Successful in 17m36s
2026-10-09 15:48:04 -04:00
bruno 4fb7c43e06 feat: chat — boutons discrets sous l'image, image en onglet d'app, point de non-lus, notification OS, suppression annulable BUG-110
CI / lint (push) Successful in 2m50s
CI / security (push) Successful in 1m36s
CI / test (push) Successful in 4m28s
CI / build (push) Successful in 1m31s
CI / e2e (push) Successful in 17m30s
2026-10-09 11:53:26 -04:00
bruno 54caa48d1f feat: chat — saisie auto-agrandissante, accusé de réception ✓✓, vignette de tuile #192 (BUG-109)
CI / lint (push) Successful in 2m52s
CI / security (push) Successful in 1m35s
CI / test (push) Successful in 4m27s
CI / build (push) Successful in 1m29s
CI / e2e (push) Successful in 17m1s
2026-10-08 23:28:08 -04:00
bruno f00a8bea8f feat: chat — suppression de post, messages privés, boîte compacte, link preview #191
CI / lint (push) Successful in 2m50s
CI / security (push) Successful in 1m35s
CI / test (push) Successful in 4m28s
CI / build (push) Successful in 1m28s
CI / e2e (push) Successful in 17m11s
2026-10-08 22:33:29 -04:00
bruno ae06436f91 feat: chat — suivi du document, chat général en onglet sidebar, onglets au-dessus du filtre #190
CI / lint (push) Successful in 2m48s
CI / security (push) Successful in 1m34s
CI / test (push) Successful in 4m33s
CI / build (push) Successful in 1m30s
CI / e2e (push) Successful in 17m5s
- **A — Suivi du document** : l'en-tête du panneau chat affiche le document
  ciblé (titre + chemin) et `followFileChat()` appelé par `renderFile()`
  re-cible le panneau ouvert à chaque changement de document.
- **B — Chat général** : onglet « Chat » (dernier) dans la sidebar,
  conversation centrale stockée dans le store #169 via les sentinelles
  `__global__/general` (`GET/POST /api/chat`) ; pastille de messages non
  lus sur l'onglet ; pièces jointes image/vidéo (`POST /api/chat/upload` :
  allow-list d'extensions, 25 MB, nom UUID ; `GET /api/chat/attachment/{name}`
  résolu contre l'allow-list) ; URL cliquables au rendu ; date/heure d'envoi.
- **C — Ordre des onglets** : la barre de filtre passe sous les onglets et
  sert de recherche dans le chat (texte + auteur) quand l'onglet Chat est
  actif (`switchSidebarTab` + `routeFilter`).
- Transport : broadcast SSE `chat_message` réutilisé (`vault __global__`
  route vers la sidebar, sinon le panneau fichier) — pas de 2ᵉ WebSocket.
- i18n FR/EN (6 clés), CSS bloc #190, `initSidebarChat()` dans l'orchestrateur.
- Tests : pytest 27 chat (12 nouveaux) ; JSDOM `filechat.test.mjs` 11 (5
  nouveaux) ; suite 1655 passed, ruff/mypy 0, validate-imports 42 modules.
- Docs : CHANGELOG [Unreleased], ROADMAP #190 → index, fiche
  `file-chat-169.md` §#190, guide « Chat général », journal des interventions.
2026-10-08 20:40:54 -04:00
bruno d0e10d4cc6 docs: journal des interventions AI #189/#169 + versions d'index resynchronisées
CI / lint (push) Successful in 2m47s
CI / security (push) Successful in 1m34s
CI / test (push) Successful in 4m24s
CI / build (push) Successful in 1m27s
CI / e2e (push) Successful in 17m37s
- `docs/ISSUES_TODOLIST.md` : deux lignes ajoutées au journal (features
  #189 mobile tableur et #169 chat par fichier, avec vérifications et
  résultats CI), exigées par le DoD pour tout passage d'IA modifiant du code.
- `docs/ROADMAP.md` : colonne version de l'index corrigée — #189 → 2.56.0,
  #169 → 2.57.0 (le hook de bump ne resynchronise pas ces rangées).
2026-10-08 18:42:31 -04:00
bruno ce1944d437 fix: coller du menu contextuel tableur muet + planchers sécurité CI (BUG-108)
CI / lint (push) Successful in 3m6s
CI / security (push) Successful in 2m18s
CI / test (push) Successful in 4m55s
CI / build (push) Successful in 3m1s
CI / e2e (push) Successful in 19m27s
BUG-108 — closeContextMenu() retirait le nœud du menu AVANT de déférencer
_menu : le retrait émet focusout en synchrone (le menu tient le focus), qui
rappelle closeContextMenu() ; le second remove() sur un nœud démonté lève
NotFoundError et avorte le handler de l'action « Coller » du viewer — le
coller par menu contextuel était silencieusement mort (régression de la
fermeture au focus #179, reproduite par l'E2E « coller une plage », CI
#850→#854). Déférencement avant retrait.

Sécurité CI (job security, run #853) :
- plancher multidict>=6.9.1 (CVE-2026-104874 ; 6.7.x préinstallée dans la
  toolcache de l'image du runner, même piège « already satisfied » que pypdf
  BUG-093) + entrée dans le garde-fou TestDependencySecurityFloors ;
- exception documentée CVE-2026-85394 (python-jose, AUCUN correctif upstream) :
  non atteignable ici, jwt.decode passe toujours algorithms=["HS256"] avec un
  secret symétrique serveur — jamais de clé publique comme clé HMAC.

Vérifié : E2E -g « coller une plage » 1/1 ; xlsx-menus 11/11,
xlsx-formula 14/14, ai 100/100, ai-quick-actions 13/13 ; pytest 1586
passés ; ruff/mypy 0 erreur ; ISSUES_TODOLIST + CHANGELOG à jour.
2026-10-07 16:49:31 -04:00
bruno 649f965c52 fix: drag & drop de fichiers — fenêtre créée sans le handler Tauri (BUG-107)
CI / lint (push) Successful in 2m46s
CI / security (push) Successful in 2m0s
CI / test (push) Successful in 4m40s
CI / build (push) Successful in 1m52s
CI / e2e (push) Successful in 16m25s
2026-10-02 23:42:01 -04:00
bruno d6fa8c7bb1 fix: injecte le nonce CSP dans les pages /docs et /redoc générées par FastAPI (BUG-106)
CI / lint (push) Successful in 2m46s
CI / security (push) Successful in 2m1s
CI / test (push) Successful in 4m40s
CI / build (push) Successful in 1m52s
CI / e2e (push) Successful in 15m57s
2026-10-02 22:04:25 -04:00
bruno bab272bb5c fix: desktop — commandes Tauri bloquées par l'ACL et crash heap à l'ouverture (BUG-104, BUG-105)
CI / lint (push) Successful in 2m45s
CI / security (push) Successful in 1m59s
CI / test (push) Successful in 4m44s
CI / build (push) Successful in 1m52s
CI / e2e (push) Successful in 16m16s
2026-10-02 20:17:20 -04:00
bruno 83e6a951dd fix: sidebar mobile passe au-dessus de la barre d outils du bas (BUG-103)
CI / lint (push) Failing after 2m11s
CI / test (push) Skipped
CI / build (push) Skipped
CI / e2e (push) Skipped
CI / security (push) Successful in 1m58s
- en mobile le sidebar de navigation (z-index 200) passait sous .mobile-toolbar (900, 64 px) : les dernieres entrees de l'arbre etaient masquees
- regle mobile .sidebar : z-index 200 -> 950 ; test de non-regression 'mobile sidebar over toolbar' dans unit.test.mjs
2026-10-02 15:34:35 -04:00
bruno 2add24a9c1 feat: onglet Accueil, menus contextuels de navigation et racine vault #158
CI / lint (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / security (push) Canceled after 0s
CI / build (push) Canceled after 0s
CI / e2e (push) Canceled after 0s
- clic sur le titre: la page d'accueil s'ouvre dans un onglet Accueil (icone Maison) epingle en tete de barre, reactivable d'un clic (onglet propre au panneau actif en split)
- page de navigation: menus contextuels des repertoires et des fichiers identiques a ceux de la sidebar, clic sur la racine d'un vault qui ouvre la vue, icone dossier a la couleur de l'arbre de navigation
- BUG-101: bloc « Keyboard shortcuts for tabs » duplique dans ui.js (un seul Ctrl+W fermait deux onglets)
- BUG-102: le menu contextuel se refermait 10 ms apres son ouverture (scroll de reflow des icones lucide)
2026-10-02 14:05:01 -04:00
bruno a50227849d feat: onglet de navigation avec facettes, tris et retour Home complet #158
CI / lint (push) Successful in 2m46s
CI / security (push) Successful in 1m57s
CI / build (push) Canceled after 0s
CI / e2e (push) Canceled after 0s
CI / test (push) Canceled after 1h50m30s
- clic sur un repertoire de l'arbre (modes focus vault et All) ouvre un onglet de navigation dedie qui coexiste avec les onglets de fichiers ouverts
- vue: sous-repertoires cliquables, facettes Vaults/Tags/Extensions (meme mecanisme que la recherche), tris Pertinence/Date, bouton Sauver; tags indexes exposes par GET /api/vault/{v}/files
- BUG-100: showWelcome re-injecte la section Raccourcis & Astuces et goHome efface la recherche globale + le filtre de la sidebar
2026-10-02 12:27:27 -04:00
bruno c5c225a68e feat: completude de l'editeur Excel - mise en forme, sortie, concurrence, cache, outils IA #156
CI / lint (push) Successful in 2m36s
CI / security (push) Successful in 1m49s
CI / test (push) Successful in 4m33s
CI / build (push) Successful in 2m39s
CI / e2e (push) Successful in 15m45s
L'editeur lisait les styles mais ne les ecrivait pas, exportait la feuille
entiere et laissait le dernier-ecrivain gagner entre processus.

- A8 : bouton Mise en forme (gras/italique/souligne, alignements, couleurs via
  selecteur natif, formats de nombre, fusion, volets figes, largeur/hauteur) et
  nouvelle route PUT .../xlsx/style (verrou, backup, swap atomique, garde de
  perte, If-Match) ; A9 : decision "pas de moteur de formule" annoncee dans
  l'UI ; A10 : undo/redo unifie, piles par fichier conservees au re-rendu
- A11 : export de la selection + Markdown/HTML/impression et recherche sur
  toutes les feuilles ; A12 : concurrence optimiste (If-Match -> 409 reparable,
  retry qui relit) ; A13 : cache des metadonnees par (chemin, mtime, taille)
- A14 : outils IA .xlsm/.csv + search_workbook, analyze_range,
  edit_xlsx_structure
- tests : test_xlsx_styles.py (17), test_spreadsheet_tools.py (34),
  TestOptimisticConcurrency/TestMetaCache, JSDOM xlsx-viewer 107/107
2026-09-30 07:04:47 -04:00
bruno 1bacfd69d9 fix: plancher pyjwt >=2.14.0 - CVE-2026-102274 corrige le job security BUG-095 2026-09-29 17:57:35 -04:00
bruno 69927176df fix: feuille xlsx vide editable avec quadrillage vierge BUG-094
CI / lint (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / security (push) Canceled after 0s
CI / build (push) Canceled after 0s
CI / e2e (push) Canceled after 0s
2026-09-29 16:34:33 -04:00
bruno 856e654306 fix: plancher pypdf >= 6.16.1 - deux DoS de ressources bloques le job security BUG-093
CI / lint (push) Successful in 2m30s
CI / security (push) Successful in 1m49s
CI / test (push) Successful in 4m17s
CI / build (push) Successful in 3m2s
CI / e2e (push) Successful in 15m9s
pip-audit bloquait sur PYSEC-2026-3910 (outlines) et PYSEC-2026-3911 (XForm),
toutes deux atteignables via backend/pdf_reader.py. Le plancher pypdf>=4.0 ne
protégeait rien : l'image Act du runner embarque 6.16.0 dans sa toolcache
Python, donc pip répondait « already satisfied » sans jamais aligner.

Au passage, le garde-fou TestSemgrepStep était en régression depuis la
désactivation de semgrep (v2.39.9) et aurait rougi le job `test` : il vérifie
désormais que l'étape n'exécute que son avertissement et que bandit et
pip-audit restent bloquants. Nouveau TestDependencySecurityFloors pour
verrouiller les planchers de sécurité (contre-preuve : pypdf remis à >=4.0).

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-09-29 13:06:53 -04:00
bruno 4de9ee038c fix: desactive l'etape semgrep du job security - core natif inexecutable sur ce runner BUG-091
CI / lint (push) Successful in 2m29s
CI / security (push) Failing after 1m45s
CI / test (push) Failing after 4m21s
CI / build (push) Skipped
CI / e2e (push) Skipped
2026-09-29 12:54:55 -04:00
bruno 140e9a679d fix: semgrep ne bloque le job security que si le core s'execute (bandit et pip-audit restent bloquants) BUG-091
CI / lint (push) Successful in 2m32s
CI / security (push) Failing after 2m17s
CI / test (push) Failing after 4m20s
CI / build (push) Skipped
CI / e2e (push) Skipped
2026-09-29 12:19:38 -04:00
bruno 435a0687d7 test: isole le garde SSRF dans les tests fetch_url - plus de dependance au DNS reel BUG-092
CI / lint (push) Successful in 2m28s
CI / security (push) Failing after 2m16s
CI / test (push) Successful in 4m16s
CI / build (push) Successful in 1m40s
CI / e2e (push) Successful in 14m53s
2026-09-29 10:05:24 -04:00
bruno d6d081c0e9 fix: semgrep 1.157.0 dans un venv isole du job security et plancher pyjwt 2.13 BUG-091
CI / lint (push) Successful in 2m27s
CI / security (push) Failing after 2m21s
CI / test (push) Successful in 4m19s
CI / build (push) Successful in 2m31s
CI / e2e (push) Successful in 15m1s
2026-09-28 21:54:12 -04:00
bruno c72f852a55 fix: semgrep epingle 1.174.0 dans le job security - CPU runner refuse les builds x86-64-v2 BUG-091
CI / lint (push) Successful in 2m30s
CI / security (push) Failing after 1m45s
CI / test (push) Successful in 4m14s
CI / build (push) Successful in 2m37s
CI / e2e (push) Successful in 14m58s
2026-09-28 19:14:08 -04:00
bruno 99779ecc08 docs: cloture documentaire #153 - changelog A6-A17, fiche, guide utilisateur et README
CI / lint (push) Successful in 2m33s
CI / security (push) Failing after 1m41s
CI / test (push) Failing after 3h11m57s
CI / build (push) Skipped
CI / e2e (push) Skipped
2026-09-28 17:48:43 -04:00
bruno 6ba04c4381 feat: troncature annoncee et lecture par fenetres des tableurs #153
CI / lint (push) Successful in 2m29s
CI / security (push) Failing after 1m39s
CI / test (push) Successful in 4m1s
CI / build (push) Successful in 1m37s
CI / e2e (push) Successful in 14m47s
- BUG-090 (#153 A8) : render_sheets() expose total_rows/total_cols,
  max_rows/max_cols et truncated ; la visionneuse affiche un bandeau
  « Feuille tronquée » (i18n FR/EN) au lieu de couper en silence, et la
  ligne d'en-têtes devient sticky (top:auto sur les numéros de ligne).
- #153 A9 : GET /api/file/{vault}/xlsx/sheet?sheet&offset&limit sert une
  fenêtre de 1 à 1000 lignes avec les vraies coordonnées A1, has_more de
  pagination et valeurs calculées A12 ; 404 feuille inconnue, 415 non-xlsx.
- Tests : TestXlsxTruncationNotice (4) + TestXlsxSheetWindow (11) avec
  contre-preuves, xlsx-viewer.test.mjs 14/14, E2E 7/7 (fixture
  sample-xlsx-large.xlsx 520 lignes), suite 1417 passed / 6 skipped,
  ruff/mypy 0, i18n parity.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-09-28 10:38:24 -04:00
bruno 06f8e63d06 feat: tableurs indexables, saisie typée et valeurs calculées #153
Les tableurs étaient invisibles à la recherche, chaque saisie devenait
du texte, et une formule n'affichait que sa formule.

- A5 : extract_indexable_text() indexe les noms de feuilles et les 20
  premières lignes (plafond 5 k caractères) pour le TF-IDF et la
  recherche sémantique. Un mot tapé dans une cellule rend le fichier
  trouvable ; un classeur chiffré s'indexe par son seul nom.
- A10 : la saisie est typée comme dans Excel — booléens
  (TRUE/FAUX/OUI/NON) et dates FR JJ/MM/AAAA en ordre jour-first, donc
  01/02/2026 est le 1er février. Une saisie ressemblant à une formule
  n'est jamais convertie (BUG-088 préservé).
- A12 : la valeur calculée par Excel s'affiche sous la formule, via une
  2e lecture data_only=True faite seulement si l'archive contient un
  <v>. Info-bulle traduite FR/EN, aucun texte d'interface côté backend.
- BUG-089 : un reindex manuel ne reconstruisait pas l'index inversé, et
  backend/search.py lisait l'index via un import par valeur — après un
  rechargement du module, la recherche écrivait dans un dict périmé.

Contre-preuves vérifiées pour A5, A10 et A12 (neutralisation de chaque
fonction → échec des tests concernés). Tests : 1402 pytest, 10 JSDOM,
4 E2E, suite E2E complète verte, ruff/mypy 0.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-09-27 22:43:24 -04:00
bruno 31d4616baf feat: garde-fous d'écriture des classeurs Excel #153 (P0)
L'édition d'un .xlsx pouvait détruire une partie du classeur, le
concurrencer en silence, ou diffuser une injection de formule.

- BUG-085 : inspect_workbook() détecte ce qu'un round-trip openpyxl perd
  (valeurs calculées en cache, slicers, contrôles, connexions, custom
  XML, signature, commentaires enrichis, macros) → xlsx_lossy_features
  exposé en lecture, bandeau FR/EN, et 409 xlsx_lossy_content sans
  `force` (confirmation explicite puis reprise). Périmètre réel
  revalidé : graphiques, images et TCD survivent au round-trip.
- BUG-086 : écriture atomique (fichier .tmp + os.replace) : un plantage
  ne peut plus tronquer le classeur, le backup reste intact.
- BUG-087 : verrou par fichier autour du read-modify-write (timeout 15 s,
  409 conflict) ; endpoint xlsx/save devenu synchrone pour que
  l'attente s'exécute dans le threadpool.
- BUG-088 : une saisie en '=' ou '@' est stockée en texte, sauf opt-in
  `allow_formula` ou le bouton f(x) de la visionneuse. Le handler
  ServiceError expose désormais code + details, que api() propage.
- BUG-084 : la suppression d'une vault purge enfin l'index inversé
  (documents fantômes qui continuaient de matcher) et is_stale() devient
  is_ready(), le nom étant trompeur (la staleness n'existe plus).

Tests : 1390 pytest, 10 JSDOM (xlsx-viewer.test.mjs, branché au CI),
3 E2E Playwright, suite E2E complète verte, ruff/mypy 0.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-09-27 20:39:12 -04:00
bruno a3973b981c securite: #87 T6-T8 fin dette — deps qualifiées, semgrep, Secure auto, CORS 2026-09-27 12:43:31 -04:00
bruno e9b7a317c1 fix: mfa/status 200 auth désactivée (garde anonymous) BUG-081 + clôture BUG-080/082/083 2026-09-27 10:35:33 -04:00
bruno 14b8032635 fix: CI lint — config-ai-keys.test.mjs rejoint l'étape JSDOM (complément BUG-082)
CI / security (push) Successful in 1m37s
CI / lint (push) Successful in 2m18s
CI / test (push) Successful in 4m8s
CI / build (push) Successful in 1m38s
CI / e2e (push) Successful in 14m28s
2026-09-27 09:44:18 -04:00
bruno 7dfe26c83d fix: CI security — echo pip-audit sans dièse (runner Act) BUG-083
CI / lint (push) Failing after 1m50s
CI / test (push) Skipped
CI / build (push) Skipped
CI / e2e (push) Skipped
CI / security (push) Successful in 1m37s
2026-09-27 09:37:34 -04:00
bruno 24229316c7 fix: CI lint — upload.test.mjs rejoint l'étape JSDOM (jsdom) BUG-082
CI / lint (push) Failing after 1m30s
CI / test (push) Skipped
CI / build (push) Skipped
CI / e2e (push) Skipped
CI / security (push) Failing after 1m33s
2026-09-27 09:23:51 -04:00
bruno 7d70e0fb75 fix: harnais E2E local anti-blocage BUG-080
CI / lint (push) Failing after 1m51s
CI / test (push) Skipped
CI / build (push) Skipped
CI / e2e (push) Skipped
CI / security (push) Failing after 1m33s
2026-09-27 09:08:58 -04:00
bruno e20fd6bf97 fix: /api/diagnostics 500 « dictionary changed size during iteration » — snapshot des dicts avant itération BUG-079
CI / lint (push) Successful in 2m3s
CI / security (push) Successful in 1m27s
CI / test (push) Successful in 4m22s
CI / build (push) Successful in 1m22s
CI / e2e (push) Successful in 13m36s
2026-09-24 17:13:40 -04:00
bruno 943005328c feat: barre d'outils de lecture epinglee, coloration syntaxique des fichiers de code et avatars predefinis (#115, #117, BUG-078)
CI / lint (push) Successful in 2m5s
CI / security (push) Successful in 1m27s
CI / test (push) Successful in 4m10s
CI / build (push) Successful in 1m23s
CI / e2e (push) Successful in 13m55s
2026-09-24 16:21:45 -04:00
bruno e1842043d8 feat: assistant IA — approbation groupee des actions, bloc d'etapes, refresh UI et bouton Stop (BUG-074, BUG-075, BUG-076, BUG-077)
CI / lint (push) Successful in 2m1s
CI / security (push) Successful in 1m25s
CI / test (push) Successful in 4m19s
CI / build (push) Successful in 1m26s
CI / e2e (push) Successful in 13m38s
2026-09-24 10:05:32 -04:00
bruno 9fb094f505 feat: refonte mobile de la section Configurations #114
CI / lint (push) Successful in 2m1s
CI / security (push) Successful in 1m26s
CI / test (push) Successful in 4m50s
CI / build (push) Successful in 1m22s
CI / e2e (push) Successful in 15m34s
2026-09-24 08:43:18 -04:00
bruno d142049216 fix: degagement mobile sous la barre de navigation du bas (clearance retargetee .main-body) BUG-073
CI / lint (push) Successful in 1m59s
CI / security (push) Successful in 1m26s
CI / test (push) Successful in 3m41s
CI / build (push) Successful in 1m21s
CI / e2e (push) Successful in 14m0s
2026-09-23 23:36:35 -04:00
bruno 8264e7ffae fix: conserver plein ecran et panneau metadonnees dans la visionneuse d'images (sidebar droite) + lanceur E2E Windows BUG-072
CI / lint (push) Successful in 2m1s
CI / security (push) Successful in 1m23s
CI / test (push) Successful in 4m27s
CI / build (push) Successful in 1m19s
CI / e2e (push) Successful in 17m45s
2026-09-23 13:43:47 -04:00
bruno 8ad8eaac71 test: spec E2E mobile pour la page Configurations BUG-071
CI / lint (push) Successful in 1m54s
CI / security (push) Successful in 1m21s
CI / test (push) Successful in 3m58s
CI / build (push) Failing after 1m22s
CI / e2e (push) Skipped
2026-09-22 22:03:42 -04:00