100 Commits
Author SHA1 Message Date
bruno 2be0b15bcf fix: partage dirigé — ACL court-circuitée après résolution Partage/ + chemin canonique au token #196
CI / lint (push) Successful in 3m0s
CI / security (push) Failing after 1m38s
CI / test (push) Successful in 4m58s
CI / build (push) Successful in 1m36s
CI / e2e (push) Successful in 19m55s
- le partage EST l'autorisation: plus de 403 'Accès refusé à la vault' pour un
  destinataire sans accès au vault émetteur (api_file, raw, download)
- chemin virtuel canonique Partage/<token>/<nom> — désambiguïse les homonymes,
  fallback par nom conservé
- 'reçu' = partagé_avec contient l'utilisateur: un admin ne voit plus les
  partages des autres comme reçus (fix File not found: Partage/…)
- +3 tests (14 total)
2026-10-10 23:11:12 -04:00
bruno de6bde1613 fix: partage dirigé — dossier Partage virtuel + ouverture en onglet #196
CI / lint (push) Successful in 3m1s
CI / security (push) Failing after 1m58s
CI / test (push) Successful in 4m43s
CI / build (push) Successful in 1m39s
CI / e2e (push) Successful in 20m28s
- _resolve_shared_file: home-<user>/Partage/<f> -> fichier source (/api/file, raw, download)
- clic dossier Partage: dépliage sans navigation (fix Directory not found)
- fichiers reçus ouverts en onglet applicatif (arbre, recherche, dashboard)
- POST /api/share: path vide/null rejeté (400) — un share path:null cassait /api/shares
- +2 tests (13 total)
2026-10-10 21:48:46 -04:00
bruno fdc9f47a0d feat: visibilité & recherche des partages dirigés #196
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
- icône share-2 bleue sur les fichiers partagés dans l'arborescence
- dossier virtuel Partage/ à la racine du home du destinataire (lecture seule /s/{token})
- recherche plein texte couvre les documents reçus (merge search_vaults, share_token)
- cache front invalidé à la création/révocation ; +2 tests non-fuite
2026-10-10 21:23:00 -04:00
bruno 49c715199d feat: partage dirigé entre utilisateurs #196
CI / test (push) Canceled after 0s
CI / security (push) Canceled after 0s
CI / build (push) Canceled after 0s
CI / e2e (push) Canceled after 0s
CI / lint (push) Canceled after 1m29s
- create_share/shared_with + validation des destinataires
- gate auth sur /s/{token} (+pdf, raw) : 404 opaque hors créateur/admin/destinataires
- GET /api/shares scopé (non-admin = créés + reçus), révocation créateur/admin
- UI : dialogue dirigé/public + destinataires, dashboard « partagé par X »
- i18n FR/EN, tests test_directed_shares.py (9), fiche feature
2026-10-10 20:14:29 -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 55a9fcc0f4 fix: retirer -f de logs du build.sh (bloquait le lock de deploiement)
CI / lint (push) Successful in 2m48s
CI / security (push) Successful in 1m34s
CI / test (push) Successful in 4m31s
CI / build (push) Successful in 1m26s
CI / e2e (push) Successful in 17m16s
2026-10-08 21:06:18 -04:00
bruno 4cdea956d7 docs: spec Assistant V2 — second cerveau (mémoire, connecteurs, proactivité)
CI / lint (push) Successful in 2m48s
CI / security (push) Successful in 1m35s
CI / test (push) Successful in 4m27s
CI / build (push) Successful in 1m26s
CI / e2e (push) Successful in 16m41s
2026-10-08 21:01:45 -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 c94f065f80 feat: chat intégré par fichier — panneau latéral, historique, temps réel SSE #169
CI / lint (push) Successful in 2m46s
CI / security (push) Successful in 1m35s
CI / test (push) Successful in 4m28s
CI / build (push) Successful in 1m27s
CI / e2e (push) Successful in 17m11s
- Store backend `backend/file_chat.py` : messages JSON par (vault, path)
  sous `data/chats/` (nom hashé SHA-256 → traversal impossible), plafond
  500 messages, texte tronqué à 4000 caractères, écriture atomique.
- Routes `GET/POST /api/file/{vault}/chat` : auth + accès vault +
  `resolve_safe_path`, schémas Pydantic (`response_model`), broadcast SSE
  `chat_message` sur le transport existant (#62) — pas de second WebSocket.
- Panneau latéral `frontend/js/filechat.js` : bouton 💬 dans la toolbar
  fichier, historique chronologique, envoi optimiste + dédoublonnage par id,
  toast « Nouveau message » si le panneau est fermé/autre fichier.
- Relais SSE dans `sync.js` (import dynamique), CSS bloc #169 (plein écran
  ≤ 768 px, input 16 px anti-zoom), i18n FR/EN (10 clés `chat.*`).
- Tests : `tests/test_file_chat.py` (15) + `tests/frontend/filechat.test.mjs`
  (6, ajouté au pipeline CI), regex toolbar-order mise à jour.
- Docs : CHANGELOG [Unreleased], ROADMAP #169 → livré + index, fiche
  `docs/features/file-chat-169.md`, guide « Discuter d'un fichier ».
2026-10-08 17:03:29 -04:00
bruno 36b4962efb feat: tableur mobile — barres repliées par défaut, bascule unique #189
CI / lint (push) Successful in 2m42s
CI / security (push) Successful in 1m38s
CI / test (push) Successful in 4m19s
CI / build (push) Successful in 1m27s
CI / e2e (push) Successful in 17m12s
Sous 768 px, la barre de menus, le ruban et le groupe Recherche sont
repliés par défaut : la barre de formule (fx), les onglets et Enregistrer
restent visibles et la grille récupère la hauteur d'écran. Un bouton
unique (#xlsx-tools-toggle) dans la barre des feuilles déplie/replie
l'ensemble (aria-expanded, état actif) ; desktop inchangé.

Ergonomie tactile : cibles ≥ 44 px, onglets en défilement horizontal,
champs de la barre de formule en 16 px (anti-zoom iOS), barre de formule
en 2 lignes quand les outils sont ouverts.

Tests : JSDOM xlsx-viewer.test.mjs (+2, 165/165), E2E mobile (repli par
défaut, dépliage, no-overflow ruban, cibles 44 px) ; openXlsx() déplie
automatiquement ≤ 768 px pour les tests desktop.
2026-10-08 15:45:39 -04:00
bruno e01e837a2a feat: secrets masqués — couverture universelle clés API/mots de passe + clic pour copier (#188)
CI / lint (push) Successful in 2m40s
CI / security (push) Successful in 1m33s
CI / test (push) Successful in 4m19s
CI / build (push) Successful in 1m31s
CI / e2e (push) Successful in 16m56s
2026-10-08 13:22:27 -04:00
bruno 634ba8a272 feat: éditeur tableur — grille A → Z par blocs, barre de menus Sheets, panneau de couleurs, création .xlsx (#180 → #186)
CI / lint (push) Successful in 2m43s
CI / security (push) Successful in 1m33s
CI / test (push) Canceled after 0s
CI / build (push) Canceled after 0s
CI / e2e (push) Canceled after 0s
Restaure et termine le lot tableur resté non committé. Il n'existait que dans un
`git stash` (24 fichiers suivis) et en fichiers non suivis (menus.js, formula.js,
color-picker.js, tests, fiches) : la 2.53.3 livrée ne le contenait donc pas. Le
stash, créé avant le commit BUG-108, n'a jamais été restauré.

#180 Redimensionnement au curseur (en-tête de bord miroité + classe de repaint),
grille thémée sur les 15 thèmes et les modes contraste élevé / sépia, menu
Fichier au niveau des onglets, barre épinglée pleine largeur.

#181 Modèle de saisie Google Sheets : sélection ≠ édition (caret masqué sans
quitter contenteditable, double-clic / F2 / première frappe qui remplace,
Entrée contextuelle, Échap qui restaure) + inventaire priorisé des écarts.

#182 Désélection fiable (clic simple sans dépendre du focus), contours de plage
non empilés (sélecteur de classes sans point), couleurs texte/fond sur une
plage, clic droit qui préserve la sélection multiple.

#183 Panneau de couleurs façon Google Sheets : palette 8 × 10, STANDARD,
PERSONNALISÉ, coche selon la luminance, sortie `#rrggbb` (une valeur HSL était
rejetée par normHex).

#184 Peinture de format complète (toutes propriétés, source sans format =
réinitialisation), sélection multi-lignes/colonnes depuis les marges, grille
étendue : colonnes A → Z d'emblée, lignes ajoutées PAR BLOCS DE 100 au
défilement jusqu'à 1000 — matérialiser 1000 lignes d'un coup = ~26 000 cellules
câblées par feuille, ce qui épuisait le tas de la suite JSDOM ; index de
cellules `ref → td`, court-circuits formule/styles, marqueur data-wired.

#185 Barre de menus : les 10 menus Google Sheets (161 entrées, 125 câblées, 36
annoncées indisponibles), ruban façon Sheets, grille unie 1 px dérivée du thème.

#186 « Créer un fichier » propose .xlsx et construit un vrai classeur OPC
(openpyxl) au lieu d'une charge utile texte illisible.

Corrections trouvées en restaurant et en exerçant le lot :
- fuite mémoire : écouteur `click` anonyme posé sur #content-area à chaque
  rendu, jamais retiré — sa fermeture retenait la grille précédente en entier ;
- sorties Markdown / HTML / Imprimer de la barre de menus inertes
  (`data-xlsx-export` jamais réparti, seul `data-xlsx-action` l'était) ;
- collision de classe `.xlsx-structure-menu` entre la barre de menus et le menu
  Structure de la barre d'outils (toute requête tombait sur un nœud masqué) ;
- curseur col/row-resize absent quand le pointeur est sur la table elle-même ;
- l'export emportait les lignes et colonnes vides du quadrillage (CSV, Markdown,
  HTML, impression) ;
- clic extérieur avalé par la grâce de 250 ms du menu contextuel (destinée au
  seul appui long tactile) ;
- une entrée indisponible laissait la barre de menus ouverte.

Tests : pytest 1595 passés / 2 ignorés ; ruff et mypy 0 erreur ; bandit 0 ;
33 suites frontend vertes (xlsx-viewer 163/163, xlsx-menus 19/19,
xlsx-formula 14/14) ; E2E complet 132 passés / 12 ignorés ; E2E xlsx-viewer
19/19.
2026-10-08 12:00:15 -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 39bad990c0 test: ai-quick-actions suit #187 - plus de flag agent sur les actions
CI / lint (push) Successful in 3m1s
CI / security (push) Failing after 2m14s
CI / test (push) Successful in 4m58s
CI / build (push) Successful in 3m17s
CI / e2e (push) Failing after 16m56s
Le test assertait encore `agent: true` sur les quick actions frontmatter,
depuis la suppression du toggle mode agent (#187, v2.53.2). Job lint CI
(run 853) en échec. Commit rattaché à la livraison 2.53.2 déjà publiée :
pas de nouvel incrément (SKIP_VERSION_BUMP).
2026-10-07 08:29:57 -04:00
bruno 431d6e9338 docs: i18n et suivi #187 - assistant agent toujours actif
CI / lint (push) Failing after 2m51s
CI / test (push) Skipped
CI / build (push) Skipped
CI / e2e (push) Skipped
CI / security (push) Failing after 2m14s
2026-10-07 08:18:45 -04:00
bruno d453969708 docs: i18n et suivi #187 - assistant agent toujours actif 2026-10-07 08:17:59 -04:00
bruno 778fa65b4c fix: assistant IA toujours en mode agent, retrait du bouton toggle #187
- Bouton « mode agent » du panneau supprimé : l'assistant est toujours
  agent (toute requête texte part sur /api/ai/bookslm/agent, les images
  restent sur /chat multimodal). Les mutations gardent la confirmation
  two-step. Deep Research et les quick actions `agent: true` basculaient
  déjà le mode en silence : le toggle ne protégeait plus rien.
- /agent résout le provider comme /chat (req.provider brut transmis à
  l'adapter pouvait désigner un fournisseur indisponible et retomber
  silencieusement sur un autre que l'étiquette SSE affichée).
- Schémas des outils mis en cache par (scope, taille du registre) avec
  copies fraîches par appelant (~27 ms de pydantic économisées par
  requête agent/MCP).
- Aide in-app réécrite, i18n FR/EN (retrait de ai.agent_mode_*),
  tests frontend adaptés (ai.test.mjs 100/100) + non-régression pytest
  (provider résolu, cache sûr).
2026-10-07 08:16:56 -04:00
bruno 69c3817579 docs: diagramme de flux de l'agent AI (boucle run_agent + pipeline call_tool + 50 outils)
CI / lint (push) Successful in 3m1s
CI / security (push) Successful in 2m12s
CI / test (push) Successful in 4m56s
CI / build (push) Successful in 2m5s
CI / e2e (push) Failing after 17m3s
2026-10-05 12:59:51 -04:00
bruno b89af917b1 fix: ordre du flag --no-cache dans build.ps1 (procedure Test refonctionne)
CI / lint (push) Successful in 2m54s
CI / security (push) Successful in 2m10s
CI / test (push) Successful in 4m48s
CI / build (push) Successful in 1m59s
CI / e2e (push) Failing after 17m13s
2026-10-04 19:58:38 -04:00
bruno d79202e698 feat: menus tableur a icones, fermeture au focus et polish mobile #179
CI / lint (push) Successful in 2m52s
CI / security (push) Successful in 2m11s
CI / test (push) Successful in 4m48s
CI / build (push) Successful in 2m0s
CI / e2e (push) Failing after 16m50s
2026-10-04 19:27:50 -04:00
bruno 4ce677902a feat: agent IA phase 4 — doublons #166, notifications externes #168 (Discord/Telegram/SMTP/webhook), taches planifiees #170
CI / lint (push) Successful in 2m53s
CI / security (push) Successful in 2m5s
CI / test (push) Successful in 4m52s
CI / build (push) Successful in 2m5s
CI / e2e (push) Successful in 16m14s
2026-10-04 13:11:25 -04:00
bruno fe9f7b49f7 feat: premier lancement ObsiGate + section Configuration harmonisée (#160)
CI / lint (push) Successful in 2m50s
CI / security (push) Successful in 2m1s
CI / test (push) Successful in 4m44s
CI / build (push) Successful in 1m54s
CI / e2e (push) Successful in 16m25s
- Premier lancement : %USERPROFILE%\ObsiGate créé et monté comme vault de
  démarrage « ObsiGate » (remplace voute_obsidian), vault_path dessus,
  racine home nommée d'après son dernier segment (fin du « bruno » codé en
  dur), champs de fenêtre préservés.
- Document « Prise en main.md » embarqué dans le binaire
  (include_str!) et écrit dans ce répertoire si absent — jamais écrasé.
- Section « 🖥️ Vaults & dossiers (Desktop) » refondue : markup à classes
  (zéro style inline), bloc CSS desktop-roots-* sur variables (motif
  webauthn-key-item), boutons .config-btn-sm primaire/secondaire,
  cibles tactiles 44px en mobile.
- Tests : test_default_first_run_config, test_welcome_doc_embedded
  (cargo test 28 passed), suites frontend vertes, E2E 123/123.
2026-10-03 10:02:16 -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 d2734dc8ce feat: gestion desktop des vaults & dossiers — retrait par menu contextuel et ajout en configuration #159
CI / lint (push) Successful in 3m2s
CI / security (push) Successful in 2m2s
CI / test (push) Successful in 4m42s
CI / build (push) Successful in 1m52s
CI / e2e (push) Successful in 15m54s
2026-10-02 21:04:17 -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 34428ea7b3 test: mobileBlockContaining ignore les commentaires CSS (CI #842)
CI / lint (push) Successful in 2m45s
CI / security (push) Successful in 1m58s
CI / test (push) Successful in 4m41s
CI / build (push) Successful in 1m52s
CI / e2e (push) Successful in 16m32s
- le helper choisissait le premier bloc media contenant la chaine 'mobile-toolbar' ; un commentaire citant ce selecteur (correctif BUG-103) le faisait retomber sur le mauvais bloc, sans la clearance .main-body (BUG-073)
- les commentaires sont maintenant retires avant la recherche de bloc
2026-10-02 15:46:05 -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 3d618eb660 ci: relance du workflow apres annulation des runs 839 et 840
CI / lint (push) Successful in 2m44s
CI / security (push) Successful in 1m57s
CI / test (push) Successful in 4m37s
CI / build (push) Successful in 1m51s
CI / e2e (push) Successful in 15m58s
2026-10-02 14:42:18 -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 5ffc9d851a fix: bouton de repli des facettes compact et icone seule qui pivote sur mobile #157
CI / lint (push) Successful in 2m44s
CI / security (push) Successful in 2m1s
CI / test (push) Successful in 4m36s
CI / build (push) Successful in 1m51s
CI / e2e (push) Successful in 15m47s
2026-10-02 08:14:48 -04:00
bruno 1e0e419210 feat: panneau de facettes repliable + facette Extensions exposee par l'API #157
CI / test (push) Canceled after 0s
CI / security (push) Canceled after 0s
CI / build (push) Canceled after 0s
CI / e2e (push) Canceled after 0s
CI / lint (push) Canceled after 9s
2026-10-01 23:07:16 -04:00
bruno 2813d546a7 feat: facette Extensions dans les facettes de recherche #157
CI / lint (push) Successful in 2m41s
CI / security (push) Successful in 2m0s
CI / test (push) Successful in 4m45s
CI / build (push) Successful in 3m4s
CI / e2e (push) Successful in 15m36s
2026-10-01 20:35:21 -04:00
bruno 19e94dfa51 chore: retire fichier test webhook
CI / lint (push) Successful in 2m40s
CI / security (push) Successful in 1m53s
CI / build (push) Canceled after 0s
CI / e2e (push) Canceled after 0s
CI / test (push) Canceled after 1s
2026-10-01 14:36:39 -04:00
bruno 49f97fc26e test: webhook apres ALLOWED_HOST_LIST
CI / lint (push) Successful in 2m43s
CI / security (push) Successful in 1m53s
CI / test (push) Successful in 4m35s
CI / e2e (push) Canceled after 0s
CI / build (push) Canceled after 22s
2026-10-01 14:30:55 -04:00
bruno 562290d922 fix: plancher urllib3>=2.8.0 pour CVE-2026-97687/97688/97689 + garde-fou CI
CI / lint (push) Successful in 2m39s
CI / security (push) Successful in 2m5s
CI / test (push) Successful in 4m35s
CI / build (push) Successful in 2m43s
CI / e2e (push) Successful in 15m26s
- backend/requirements.txt : plancher urllib3>=2.8.0 (3 CVE corrigées)
- .gitea/workflows/ci.yml : documentation des nouveaux planchers
- tests/test_ci_workflow.py : garde-fou urllib3 ajouté dans TestDependencySecurityFloors

Corrige l'échec du job security (pip-audit bloquant sur urllib3 2.7.0)
2026-10-01 12:20:46 -04:00
bruno 66a5505965 fix: correction raccourci palette + filtrage ext/vault/tag dans palette fichiers
CI / lint (push) Successful in 2m40s
CI / security (push) Failing after 1m53s
CI / test (push) Successful in 4m36s
CI / build (push) Successful in 1m48s
CI / e2e (push) Successful in 17m29s
- Correction du raccourci clavier inversé dans l'aide :
  Ctrl+Shift+Space → Palette de fichiers (navigation rapide)
  Ctrl+Alt+Space → Palette de commandes
- Ajout du support des filtres ext:xxx, vault:nom, tag:monTag dans la palette de fichiers
- parseQuery étendu pour gérer les opérateurs de filtrage
- Filtrage client-side par extension et tag dans searchFiles et searchBrowseGlobal
- Backend : suggest_titles retourne les tags pour chaque suggestion
- Schema TitleSuggestion : ajout du champ tags
- Placeholders mis à jour pour indiquer les nouveaux filtres disponibles

Fixes : raccourci inversé, filtrage par extension/vault/tag dans palette fichiers
2026-10-01 10:29:42 -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 383ffa6a65 feat: menu contextuel et selection type Excel dans la grille XLSX #155
CI / lint (push) Successful in 2m31s
CI / security (push) Failing after 1m46s
CI / test (push) Successful in 4m20s
CI / build (push) Successful in 1m41s
CI / e2e (push) Successful in 15m30s
2026-09-29 16:43:39 -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 5c2ae26a74 docs: corrige la plage de versions de #154 dans la roadmap
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 15:26:10 -04:00
bruno 3f52b56251 refactor: extraction des modules xlsx, lien dashboard-grille et inspecteur redimensionnable #154 2026-09-29 15:25:38 -04:00
bruno 72da123a51 feat: undo/redo, chargement IntersectionObserver et ARIA pour la visionneuse XLSX #154
CI / lint (push) Successful in 2m30s
CI / security (push) Failing after 1m45s
CI / build (push) Canceled after 0s
CI / e2e (push) Canceled after 0s
CI / test (push) Canceled after 19s
2026-09-29 15:01:00 -04:00
bruno e94af0369b feat: inspecteur droit pour le tableau de bord XLSX #154
CI / lint (push) Successful in 2m30s
CI / security (push) Failing after 1m46s
CI / build (push) Canceled after 0s
CI / e2e (push) Canceled after 0s
CI / test (push) Canceled after 1h32m51s
2026-09-29 14:56:08 -04:00
bruno 8da65611cb feat: dialogues themes et conflits non bloquants pour la visionneuse XLSX #154
CI / lint (push) Successful in 2m31s
CI / security (push) Failing after 1m46s
CI / test (push) Successful in 4m17s
CI / build (push) Successful in 1m40s
CI / e2e (push) Canceled after 42s
2026-09-29 14:50:47 -04:00
bruno 605060c51d feat: visionneuse XLSX - ruban groupe, onglets permanents et badges d'etat #154
CI / lint (push) Successful in 2m30s
CI / security (push) Failing after 1m45s
CI / test (push) Successful in 4m17s
CI / build (push) Successful in 1m40s
CI / e2e (push) Successful in 15m10s
2026-09-29 14:30:36 -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 290d62da4e fix: continue-on-error sur l'etape semgrep - le core natif ne doit plus bloquer la CI BUG-091
CI / lint (push) Successful in 2m29s
CI / security (push) Failing after 2m16s
CI / test (push) Failing after 4m17s
CI / build (push) Skipped
CI / e2e (push) Skipped
2026-09-29 12:43:21 -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 267a33d43b fix: deplace le venv semgrep hors de /tmp (fs noexec du runner) BUG-091
CI / lint (push) Successful in 2m27s
CI / security (push) Failing after 2m15s
CI / test (push) Successful in 4m21s
CI / build (push) Successful in 1m40s
CI / e2e (push) Successful in 15m33s
2026-09-29 10:37:01 -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 dbf935bec0 fix: diagnostic semgrep-core dans le job security - CPU, disque et exec brute traces BUG-091
CI / lint (push) Successful in 2m31s
CI / security (push) Failing after 2m16s
CI / test (push) Failing after 4m21s
CI / build (push) Skipped
CI / e2e (push) Skipped
2026-09-29 09:21:25 -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 c4b8e66206 feat: tableau de bord classeur - plages nommees, TCD/graphiques et KPI par feuille #153
A17 — nouveau endpoint GET /api/file/{vault}/xlsx/dashboard (read_workbook_
dashboard : plages nommees avec portee depuis defined_names read_only,
comptage graphiques/TCD par parts OPC, stats par feuille bornées 500x40 :
cellules/lignes/colonnes/formules/numerique + 8 premieres valeurs en cartes
KPI) et panneau frontend toggled depuis la toolbar (table des plages,
cartes KPI par feuille, hint actions IA). Bouton absent pour .csv et
formats en lecture seule ; le menu structure est saute quand le bouton
n'existe pas. i18n FR/EN (xlsx.dashboard_*), 8 tests backend + 2 tests
JSDOM + contre-preuve (5 echecs sur neutralisation), ruff/mypy 0.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-09-28 16:40:09 -04:00
bruno ca6407e0c0 feat: formats tableur additionnels - xlsm editable, xls/ods lecture seule, csv editable #153
A16 — la visionneuse tableur accepte quatre formats de plus : .xlsm est
servi et sauvegarde comme un .xlsx avec keep_vba=True (les macros
survivent, la porte lossy est levée pour ce format) ; .xls (xlrd) et .ods
(odfpy) sont rendus en lecture seule (xlsx_readonly, wiring d'édition
désactivé) ; .csv devient éditable via render_csv_table (grille A1
identique au viewer) et PUT /api/file/{vault}/csv/save (réécriture csv
RFC 4180, extension de grille, valeurs stockées telles quelles). 12 tests
backend + contre-preuve (4 échecs sur neutralisation du service CSV),
JSDOM 33/33, ruff/mypy 0.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-09-28 16:27:10 -04:00
bruno dff32a97ee feat: styles minimaux, fusions et volets figes dans la visionneuse xlsx #153
A15 — le rendu tableur lit les metadonnees du classeur (une charge en mode
normal par feuille) et les restitue : styles inline data-driven (couleur de
police en premier, fond, gras/italique, format numerique signale en mono),
alignements non-defaut, plages fusionnees (rowSpan/colSpan cote client) et
ancrage des volets figes (sticky rows/cols). Le chargement lazy replie les
metadonnees de chaque fenetre. Contrat API : styles/aligns = {ref: css},
merges = [ranges], freeze = ancre. 9 tests backend + contre-preuve (5 echecs
sur neutralisation), JSDOM 33/33.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-09-28 16:07:58 -04:00
bruno d5c528fead feat: structure des classeurs Excel editable depuis la visionneuse #153
A14 : service mutate_xlsx_structure (batch ordonné d'actions
sheet_add/sheet_rename/sheet_delete/sheet_duplicate et
row/col_insert/delete, une seule réécriture verrouillée et atomique,
409 lossy sans force, backup, dernier sheet protégé) ; endpoint
PUT /api/file/{vault}/xlsx/structure (1-50 actions/requête) ;
menu « structure » dans la visionneuse : ajout/renommage/duplication/
suppression de feuilles et insertion/suppression de ligne/colonne à
partir de la cellule active, confirmations explicites pour les
destructions, re-rendu serveur après succès, reprise force après
confirmation 409.

Vérifié : test_xlsx_structure.py 11 (ops, gardes, atomicité du batch,
409 lossy + force) + contre-preuve (garde dernier sheet neutralisée ->
1 échec), xlsx-viewer.test.mjs 33/33 (3 nouveaux), ruff 0, mypy 0,
i18n parity, validate-imports.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-09-28 12:53:15 -04:00
bruno 38f39a10ae feat: tri, filtre, recherche et export CSV dans la visionneuse XLSX #153
A13 (affichage seul, le classeur n'est jamais réécrit) : clic sur un
en-tête pour trier la colonne (asc/desc, numérique si toutes les valeurs
le sont, localeCompare fr sinon — les cellules modifiées suivent leur
ligne) ; l'unique champ de recherche filtre les lignes ET surligne les
occurrences (marque <mark>, navigation ↑/↓/Entrée, compteur i18n,
insensible à la casse par défaut, bouton Aa) ; bouton « Réinitialiser »
qui re-rend le fichier (vérité serveur) ; export CSV de la feuille
visible (BOM UTF-8, échappement ;/" et retrait des ombres de valeurs
calculées).

Vérifié : xlsx-viewer.test.mjs 30/30 (5 nouveaux) + contre-preuves
(tri neutralisé -> 1 échec, filtre neutralisé -> 1 échec), validate-imports,
i18n parity (xlsx.find_*, xlsx.sort_*, xlsx.csv_export).

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-09-28 12:28:09 -04:00
bruno 48e023ba25 feat: navigation clavier et barre de formule dans la visionneuse XLSX #153
A7 : barre de formule sous la barre d'outils (nom de cellule active A1 +
miroir du contenu, édition live, Entrée valide, Échap annule puis
refocalise) ; flèches et Tab déplacent la cellule active dans les 4
directions (Shift inverse Tab), outline persistant sur la cellule active
quand le focus passe à la barre ; Maj+Entrée ne valide plus (réservé au
multiligne A7+). td.tabIndex=0 pour la focalisation clavier.

Vérifié : xlsx-viewer.test.mjs 25/25 (6 nouveaux), E2E 9/9 (barre +
flèches + Échap sur fixture réelle), validate-imports, i18n parity
(xlsx.formula_bar_placeholder, xlsx.active_cell).

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-09-28 12:18:24 -04:00
bruno 011ec84f23 feat: outils IA de lecture et d'edition des classeurs existants #153
A6 : list_xlsx_sheets (noms + dimensions + truncated), xlsx_to_markdown
(table bornee 100x20 pour le contexte LLM), update_xlsx_cells et
append_xlsx_rows (WRITE + confirmation, via edit_xlsx_cells : verrou,
ecriture atomique, neutralisation des formules, 409 lossy). Les lignes
ajoutees sont coercees comme dans le viewer (A10). Labels de step
ai.step.xlsx_* FR/EN ; update_xlsx_cells/append_xlsx_rows branches sur
MUTATING_TOOLS et FILE_WRITE_TOOLS (refresh viewer via obsigate:file-written).

Tests : test_spreadsheet_tools.py 17 (risque, confirmation, persistance,
garde formule heritee, coercion) + contre-preuve (cells vide -> 2 echecs).
ruff 0, mypy 0, i18n parity, validate-imports.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-09-28 12:05:16 -04:00
bruno 472ea9d309 feat: chargement à la demande des lignes cachées des tableurs #153
CI / lint (push) Successful in 2m24s
CI / security (push) Failing after 1m39s
CI / test (push) Successful in 4m0s
CI / build (push) Successful in 1m37s
CI / e2e (push) Successful in 15m34s
A9bis : sous une feuille tronquée, un pied de page « N lignes affichées
sur M · Charger la suite » fetch la fenêtre suivante (limit=500) au clic
ou à l'approche du bas du tableau (sentinelle de défilement, marge 120px).
Les lignes ajoutées passent par le même pipeline d'édition que le rendu
initial (setupCell factorisé) : éditables et sauvegardables immédiatement.
Fetch échoué → bouton restauré (retry) + toast ; feuille complète → pied
de page masqué (class done).

Vérifié : xlsx-viewer.test.mjs 19/19 (5 nouveaux, contre-preuve
wireLazyRows désactivé → 5 échecs), E2E 8/8 (A520 visible et éditable
après clic), validate-imports 40 modules, unit.test.mjs 12/12, i18n parity.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-09-28 11:52:42 -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 4c4b1222d5 chore: ignore les diagrammes E2E générés (excalidraw)
CI / lint (push) Successful in 2m23s
CI / security (push) Failing after 1m48s
CI / test (push) Successful in 3m49s
CI / build (push) Successful in 2m28s
CI / e2e (push) Successful in 14m5s
2026-09-27 14:46:09 -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 b6e2029770 fix: E2E node-direct, timeouts réalistes 25/30 min (complément BUG-080)
CI / lint (push) Successful in 2m22s
CI / security (push) Successful in 1m37s
CI / test (push) Successful in 4m48s
CI / build (push) Successful in 1m33s
CI / e2e (push) Successful in 14m3s
2026-09-27 11:28:35 -04:00
bruno 6b878caff3 securite: #87 T5c script-src sans unsafe-inline (nonces T5b)
CI / lint (push) Successful in 2m18s
CI / security (push) Successful in 1m37s
CI / test (push) Successful in 4m32s
CI / build (push) Successful in 1m34s
CI / e2e (push) Successful in 14m22s
2026-09-27 10:36:00 -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 d70ecd0968 securite: #87 T5b nonces CSP prets pour bascule (sans changement) 2026-09-26 22:44:12 -04:00
bruno 36a4030c09 securite: #87 T5a supprime 16 handlers inline au profit de listeners (CSP inchangee) 2026-09-26 22:32:01 -04:00
bruno 330462e7a5 docs: #87 T4 consigne resultats E2E locaux (108/108 desktop, 10/10 mobiles cibles) 2026-09-26 22:22:31 -04:00
bruno 922dfa2e79 test: #87 T4 E2E XSS partage et lecteur + script serveur E2E avec progression 2026-09-26 21:46:16 -04:00
bruno 34fce932cb securite: #87 T3 cookies Secure centralises + CORS atteste (defaut inchange) 2026-09-26 18:37:19 -04:00
bruno 18b1e13f34 test: #87 T2 durcissement concurrence users.json et budget temps regex 2026-09-26 18:34:06 -04:00
bruno 7bee4a237d ci: #87 T1 bandit et npm audit bloquants, 5 suites frontend au CI 2026-09-26 18:30:04 -04:00
bruno d6cca2b1af feat: #85 T10 persistance etat (verrous stores, ratelimit SQLite) et cloture refonte 2026-09-26 18:10:10 -04:00
bruno 58312e64da refactor: #85 T9 extrait realtime et render vers modules dedies (comportement inchange) 2026-09-26 16:59:25 -04:00
bruno 3b0927a8c9 refactor: #85 T8 extrait vaults-history-conflicts vers backend/routers (comportement inchange) 2026-09-26 14:46:55 -04:00
bruno 6e527c371d refactor: #85 T7 extrait le domaine config vers backend/routers (comportement inchange) 2026-09-26 14:33:40 -04:00
bruno 6cccdc1f34 refactor: #85 T6c extrait media-pdf-export vers backend/routers (comportement inchange) 2026-09-26 14:06:52 -04:00
bruno 0abc17e9f2 refactor: #85 T6b extrait mutations fichiers-dossiers vers backend/routers (comportement inchange) 2026-09-26 13:51:36 -04:00
bruno b83d8dacdf refactor: #85 T6a extrait lecture fichiers vers backend/routers (comportement inchange) 2026-09-26 13:43:53 -04:00