From 7eb92d830a10a569d38867d6ff9a9bce65c0531f Mon Sep 17 00:00:00 2001 From: Thierry Date: Sat, 6 Jun 2026 23:58:53 +0200 Subject: [PATCH] docs: catch-up CHANGELOG + plan/ROADMAP/README banners (4 + 6 June) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vital docs all stopped at 2 June. This catches them up so a future session (after the maintenance pause) reads the real current state. - CHANGELOG.md: two narrative entries — 4 June (8-PR day: THI-234 admin analytics, THI-341 mobile nav + avatar menu, THI-344 editable display_name, THI-346 dropdown fix, THI-347 part 3 delete tickets + THI-334 root-cause) and 6 June (pre-pause audit + THI-342 mobile fix + the api/* untouched and THI-345/347 defer decisions). - docs/plan.md / docs/ROADMAP.md / docs/README.md: banner prepend with the 6 June + 4 June segments (FR/EN/FR), preserving the prior history chain. Docs-only (no src/api/supabase/config). Voie C. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ docs/README.md | 2 +- docs/ROADMAP.md | 2 +- docs/plan.md | 2 +- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b53c432..bf982d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,34 @@ --- +## 🔍 6 juin 2026 — Audit complet avant la pause : on vérifie que tout tient avant de couper (THI-342) +*PR #375 · security-auditor 9.4/10 · content-auditor · mobile-responsive-auditor · route-attack-auditor · Sentry · e2e Chrome* + +Avant une pause de maintenance (l'outil reste en ligne mais sans correctifs rapides pendant un temps), on a passé l'application au crible pour garantir que **tout ce qui est en ligne fonctionne parfaitement**. Cinq angles d'audit en parallèle + un test de bout en bout dans le navigateur. + +- **Sécurité : solide.** Audit black-hat complet (OWASP, CSP, RLS, auth, chaîne d'approvisionnement) → **9.4/10, zéro faille critique**. Les 8 livraisons du 4 juin sont toutes confirmées sûres. Un signalement « SSRF » sur le tunnel d'erreurs s'est révélé être un **faux positif** après vérification du code (l'URL de destination est figée en dur, la valeur fournie par le client ne l'atteint jamais). **Décision : on ne touche pas aux routes serveur** — modifier du code déjà sûr juste avant une pause ajoute du risque pour un gain nul. +- **Mobile (THI-342) : corrigé.** Le formulaire de signalement débordait sur iPhone. Cause : le champ de description était en 14px, et **iOS Safari zoome automatiquement tout champ sous 16px** au focus, ce qui décalait la mise en page. Passé en 16px sur mobile (14px conservé sur ordinateur). Au passage, une cible tactile de menu sécurisée à 44px. +- **Honnêteté de diagnostic.** Une seconde hypothèse (le nom de fichier du screenshot qui déborderait) a été **testée puis écartée empiriquement** — la troncature CSS le gère déjà. On documente ce qu'on a vérifié, pas ce qu'on suppose. +- **Contenu pédagogique.** Deux petits défauts d'affichage repérés dans la leçon « Scripts » (le simulateur n'exécute pas encore `./script.sh` ni la redirection `2>`) : **non bloquants** (la leçon se valide quand même), à polir à la reprise. +- **Monitoring & santé.** Sentry de production : **propre** (un seul événement bénin, auto-réparé). Parcours cœur (accueil → tableau de bord → leçon → **le terminal s'exécute**) : zéro erreur. + +Décision produit : les chantiers nouveaux et **irréversibles** (suppression de compte RGPD THI-345, gestion CRUD des classes/institutions THI-347) sont **différés** après la reprise — on ne met pas de l'irréversible en ligne juste avant une fenêtre sans correctifs. + +--- + +## 🗂️ 4 juin 2026 — Journée dense : tableau de bord analytics, navigation mobile repensée, profil éditable +*PRs #368→#374 · THI-234 · THI-341 · THI-344 · THI-346 · THI-347 · THI-334* + +Huit livraisons en une journée, toutes vérifiées (sécurité, UI, revue de code, validation visuelle). + +- **Tableau de bord analytics (THI-234)** : widgets « Santé Supabase » + carte de chaleur d'activité dans le panneau d'administration — agrégats anonymes, aucune donnée individuelle, via des fonctions base sécurisées (rôle vérifié côté serveur). Budget 0 €. +- **Navigation mobile repensée (THI-341)** : la barre latérale se concentre sur l'essentiel (tableau de bord, référence, **modules/leçons**, environnement) ; le secondaire (profil, paramètres, aide, signalements, déconnexion) passe dans un **menu avatar façon GitHub**. Construit en React/Tailwind « maison » pour rester compatible avec la politique de sécurité stricte (pas de styles injectés). +- **Profil éditable (THI-344)** : on peut enfin modifier son nom affiché depuis « Mon Profil », avec correction du contraste du champ en thème sombre. +- **Correctif menu (THI-346)** : suppression d'une barre de défilement redondante sur le menu avatar. +- **Suppression de signalement + fix racine (THI-347 volet 3 / THI-334)** : le mainteneur peut supprimer un ticket depuis le triage. La migration associée corrige aussi **à la racine** une pollution de la base par les tests (le nettoyage de fin de test échouait silencieusement faute de droit de suppression). + +--- + ## 📋 2 juin 2026 — Tes signalements suivis : l'utilisateur voit où en sont ses retours (THI-325) *PR #366 · /app/support · useMySupportTickets · ticketDisplay (source unique badges/libellés) · security-auditor 9.6/10 (isolation RLS prouvée REST+JWT) + ui-auditor + code-review + Voie A desktop/tablette/mobile 390px* diff --git a/docs/README.md b/docs/README.md index 5b8ae2a..1574ff7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ # Documentation Index — Terminal Learning -> Last updated: 2 juin 2026 CEST — **🗂️ Sprint 2.C étape 4 — triage signalements super_admin (THI-320, PR #364)** : section « Signalements » dans `/app/admin` (liste + filtre statut + capture re-signée au read + statut journalisé `admin_audit_log`). **Système support complet** (formulaire → stockage → email → triage). Dropdown statut : Radix Select écarté (style inline → CSP `style-src` stricte) → `` natif `[color-scheme:dark]`, CSP intacte, 0 dép. Gates : security 9.5/10 · ui SHIP · mobile · code-reviewer · Voie A e2e « 2 sens » (desktop+mobile). Suite : THI-325 (visibilité user). — **Update précédent (1er juin 2026 CEST)** — **📧 Sprint 2.C étape 3 — notification email support (THI-319, PR #360)** : à la création d'un ticket, le super_admin reçoit un email (Resend). Implémenté en **route Vercel Edge** `api/support/notify.ts` (pivot vs Edge Function Supabase : clé Resend déjà en env Vercel + `api/*` déjà serverless → 0 plateforme/dépendance/secret nouveau). **Autorisation déléguée à RLS** (JWT user forwardé à PostgREST, ligne renvoyée seulement si owner/super_admin, aucun `service_role`). Anti-replay 60s + rate-limit 10/min/IP + description HTML-escaped + `no-store` + best-effort. **3 gates 0C/0H** (security 9.2/10 · route-attack ship · code-review clean) + **email réellement reçu** (Gmail MCP) + smoke prod 200. **THI-319 Done — reste l'étape 4** (section Tickets AdminPanel, THI-320). Aussi 1er juin : session fiabilité (THI-310/315/313, PRs #353-355), cohérence catalogue fermant THI-293 (THI-316, #357), filtre crawler Sentry (THI-317, #358). — **Update précédent (30 May 2026 ~14h CEST)** — **🚀 Sprint 2.C étape 2 — signalement in-app (PR #326)** : migration 030 bucket privé `support_screenshots` + 5 RLS `storage.objects` + `SupportTicketModal` (focus-trap + Escape, form 3 champs, disclaimer PII, trigger Sidebar « Aide & feedback » gated `user`) + `submitTicket` (upload → URL signée 7j → insert + cleanup orphelin). **3 audits gate-zero ALL GREEN** (supabase-backend SHIP 11 tests adversariaux prod 0C/0H + ui clean + security 9.3/10), **code-review** 0 critical (2 fixes), **Context7** API Storage vérifiée. Tests **1765 → 1780 PASS** (8 composant + 7 RLS bucket empiriques PROD). CHANGELOG catch-up #319-325 (drift 29/05). Sprint 2.C reste 2 étapes (Resend → AdminPanel). Voir CHANGELOG.md / plan.md. — **Update précédent (24 May 2026 ~20h CEST) — 🧠 AI Tutor par rôle livré — Stage B1 + Stage B2** : 7 PRs mergées même jour (#287 → #293). Stage B1 (#290, THI-260) = eval matrix frontier 2025-2026 sur 10 modèles × 14 fixtures, $0.62 USD, 2 modèles 8/8 PASS (GPT-5.5 440 ms + Opus 4.7 premium). Stage B2 (#291, THI-275) = 3 system prompts FR cloisonnés par rôle + dispatcher + fallback student defense-in-depth + 17 tests + 4 fixtures injection `` × 4 langues. `prompt-guardrail-auditor` Sonnet trouve 2 CRITICAL **fixés avant merge** (ghost block + DELIMITER_RX gap). 2 nouveaux agents : `legal-compliance-auditor` Opus 4.7 (THI-270 #288) + `user-forensics-auditor` Sonnet (THI-274 #293). Tests 1697 PASS (+57). Sprint 2.B prochaine session : `institution_admin` lite + `institution-rbac-auditor` gate-zero. Voir CHANGELOG.md / STORY.md pour la narrative complète. — **Update précédent (19 May 2026 ~21h CEST) — 🚀 Sprint 2.A Teacher workflow 75% shipped (étapes 1+2+2.bis+2.ter live)** : 5 PRs mergées journée (#267 `.env.example` exhaustif + #268 Teacher Dashboard CRUD `/app/teacher` + migrations 020/021 + #269 role-aware nav hub + login redirect safe + #270 adaptive default route per role super_admin → `/app/admin` + #271 docs CHANGELOG). Tests 1545 → 1604 (+59). Cascade ALL GREEN : security-auditor 9.4-9.5/10 · ui-auditor SHIP-READY · rbac-flow-tester 11/11 E2E PASS · happy path RPC empirique · Voie A Chrome MCP · Sourcery PASS. 6 follow-ups Linear créés (THI-237/238/239/240/241/242). Next : Sprint 2.A étape 3 = page `/app/join` consommant `join_class_by_code` RPC (pré-requis : agent `classroom-workflow-auditor` + THI-239 Vitest regression net + Voie A multi-personas). Voir CHANGELOG.md pour détails. — **Update précédent (16 May ~14h30 CEST) — 🚀 Sprint 2 étape 2/N — THI-153 ✅** : PR [#234](https://github.com/thierryvm/TerminalLearning/pull/234) mergée — cleanup UI bundle (umbrella audit). 4 items cherry-picked : `--github-red` CSS var unique source + migration AI/auth red palettes · UserMenu logout focus ring rouge → emerald · shadcn dead slots documentés · `sonner` désinstallé · **bonus brand fix** « Terminal Master » → « Terminal Learning » dans Layout mobile (`/app`). Sourcery review addressed (DestructiveActionButton helper local + emerald token rationale). 3 tickets backlog créés : THI-177 (pré-i18n discipline gate Phase 9 admin) · THI-178 (SEO longue traîne SSG Phase 10+) · THI-179 (securityheaders A+ COEP post-LTI 7c). Validation ui-auditor SHIP-READY · 1386 tests passed 0 errors · Landing chunk 7.33 kB gzip stable. Sprint 2 ordre verrouillé : THI-118 ✅ → THI-153 ✅ → **THI-131 Phase 7c LTI (next)** → THI-42 → THI-77/78. — **Update précédent (16 May ~10h45 CEST) — Sprint 2 démarré — deadline 10 juin — THI-118 ✅** : landing LCP regression fix mergée (PR [#232](https://github.com/thierryvm/TerminalLearning/pull/232)). Diagnostic Chrome DevTools MCP : LCP element = hero `

` sous-titre (texte), 98.9 % render delay, fuites `landingContent.ts` (`.reduce()` sur `commandCatalogue` forçait chunk curriculum eager) + `UserMenu`/`LoginModal`/`PWAInstallModal` eager. Fix : hardcoder + drift guard test + `React.lazy` modals. **Bundle Landing 27.29 → 7.33 kB gzip (−73 %)**, curriculum chunk plus dans le graph landing. Le test drift a caught un `TOTAL_LESSONS` 64 → 65 silencieux. Sprint 2 ordre verrouillé : THI-118 ✅ → THI-153 cleanup UI bundle (~75 min) → THI-131 Phase 7c LTI → THI-42 Profile Hub → THI-77/78 admin heatmaps. — **Update précédent (16 May ~10h CEST) — Sprint 1 Phase 7b lockdown CLOS à 4/4** : THI-148 (V1.0.1 méta-plateforme) ✅ → THI-144 (v1.1.0 anti-frictions + ADR-008) ✅ → THI-112 (onboarding AiKeySetup + AiConsentModal + AiSettings + Privacy section + M3-AI fix) ✅ → **THI-113 (audit final triple + H1 fix sentry-tunnel scrubber symétrique)** ✅. Score IA security : 8.7/10 (baseline 10 mai matin) → 9.0 → 9.1 → 9.3 → **9.4/10** post-H1 fix. Rapport audit final dans `docs/audits/ai-tutor-v1-2026-05-16.md` — verdict ALL CLEAR (3 agents : security-auditor + prompt-guardrail-auditor + ui-auditor). Prochaine étape : Phase 7c LTI activation (gate H4-AI jsonwebtoken). Voir CHANGELOG.md / STORY.md pour la narrative complète. > This directory contains active project documentation. For historical/stale docs, see `.archive/`. --- diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 682162d..c497439 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -1,6 +1,6 @@ # Roadmap — Terminal Learning -> **Last updated:** 2 June 2026 CEST — 🗂️ **Sprint 2.C step 4 shipped — super_admin ticket triage (THI-320, PR #364)**: "Signalements" section in `/app/admin` (list + status filter + description + screenshot re-signed at read + status change logged to `admin_audit_log`). **Support system complete** (form → encrypted storage → maintainer email → triage). Status dropdown: Radix Select **rejected** (injects inline styles → would break the strict `style-src` CSP, THI-120 hardening) in favour of a native `` with `[color-scheme:dark]` — CSP fully intact, 0 dependency. Gates: security-auditor 9.5/10 · supabase-backend (inline) · ui-auditor SHIP · mobile-responsive · code-reviewer · **Voie A e2e super_admin "both directions"** (submit-with-screenshot → triage → status round-trip → audit confirmed → image loaded with no CSP violation, desktop + mobile). Next: user visibility on their own tickets (THI-325). — **Previous update (1 June 2026 CEST)** — 📧 **Sprint 2.C step 3 shipped — super_admin email notification on support ticket (THI-319, PR #360)**: implemented as a **Vercel Edge route** (`api/support/notify.ts`, not a Supabase Edge Function — code-verify showed the Resend key already lives in Vercel env + `api/*` already hosts serverless routes → 0 new platform/dependency/secret). **Authorization delegated to RLS** (user JWT forwarded to PostgREST; row returned only if owner/super_admin, no `service_role`). Anti-replay freshness 60s + rate-limit 10/min/IP + HTML-escaped description + `Cache-Control: no-store` + best-effort (failed email ≠ lost ticket). **3 gates 0C/0H** (security-auditor 9.2/10 · route-attack-auditor ship · code-reviewer clean) + **real email received** (Gmail MCP verified) + prod smoke 200. Resend free tier (3000/mo). **THI-319 Done — Sprint 2.C: step 4 remaining** (AdminPanel tickets section, THI-320). Also 1 June (reliability + coherence): reliable signOut + async-import hardening + mobile lesson nav (THI-310/315/313, PRs #353-355), catalogue validator coherence closing THI-293 (THI-316, PR #357), Sentry crawler/bot filter (THI-317, PR #358). — **Previous update (30 May 2026 ~14h CEST)** — 🚀 **Sprint 2.C step 2 shipped (PR #326)**: in-app support reporting. Migration 030 private `support_screenshots` bucket + 5 `storage.objects` RLS policies (user own folder via `foldername[1]=auth.uid()` / super_admin all GDPR Art.17). `submitTicket.ts` (upload → 7d signed URL conforming to the 029 M1 DB constraint → insert + best-effort orphan cleanup). `SupportTicketModal` (focus-trap + Escape, 3-field form, PII disclaimer, Sidebar "Aide & feedback" trigger gated by `user`). **3 gate-zero audits ALL GREEN**: `supabase-backend-auditor` SHIP (**11 adversarial live-prod tests** — path traversal/MIME spoof/oversize/cross-user signed URL all blocked, 0C/0H) + `ui-auditor` clean + `security-auditor` **9.3/10**. **code-review** 0 critical (2 fixes: double-label a11y + DRY). Context7-verified Storage API current. Tests **1765 → 1780 PASS** (8 component + **7 empirical PROD RLS bucket** REST+JWT incl. T7 cross-user signed URL non-regression). Step 3/4 follow-ups tracked (non-blocking): server-side magic-bytes validation + upload/insert rate limiting (API4, 2.D backlog) + CSP `img-src` supabase.co at step 4 (screenshot render). **CHANGELOG catch-up #319-325** (29/05 drift flagged at shutdown). **Sprint 2.C: 2 steps remaining** (Resend Edge Function → AdminPanel tickets section). — **Previous update (28 May 2026 ~late CEST)** — 🚀 **Post-reset session: 3 PRs shipped (#314 → #316) + Opus 4.8 switch**. **PR #314** B2B platform vision Option D Hybrid (549-line strategy doc, Voie C) + **13 Linear tickets** (THI-282 Phase X umbrella + 8 sub X1→X6 + THI-291/292/293/294 backlog). **PR #315 Sprint 2.C step 1** = `support_tickets` table + scoped RLS + audit trigger (migration 028 base + 029 hardening, security-auditor Opus 8.8→9.4/10: H1 trigger guard + H2 WITH CHECK + M1 screenshot_url Storage-only XSS defense + M2 super_admin DELETE GDPR Art.17 + M3 status/resolved coherence). **15/15 empirical PROD vitest** (RLS REST+JWT). Full regression **1744/1764 PASS**. **PR #316 meta-audit 20 agents post-4.8**: new `supabase-backend-auditor` (Opus, gate-zero Edge Function Deno + Storage RLS + file upload, BEFORE step 3 Resend + X3b import), `linear-sync` rewritten (admits MCP failure instead of guessing), README model sync, anti-downgrade pin 4.7→4.8. **Hard rule @thierry: NEVER Haiku** (0 Haiku / 12 Sonnet / 8 Opus). **MCP Supabase fixed** (wrong gmail/Ankora account → reconnected TL, Ankora SQL near-miss auto-rollback 0 damage). **Sprint 2.C: 3 steps remaining** (SupportTicketModal UI + support_screenshots bucket → Resend Edge Function → AdminPanel tickets section). — **Previous update (27 May 2026 ~16h CEST)** — 🔧 **Marathon 27 May session : 6 PRs shipped (#305 → #310)** : Sprint 2.B reliquats hotfix super_admin RPC + Sprint 2.B.2 UX scope badge + Sprint 2.B.3 sidebar "Mes outils" collapsible THI-240 + UserMenu hover fix + agent doctrine aligned (0 Haiku / 12 Sonnet / 7 Opus). **ui-auditor Haiku → Sonnet upgrade** (1st post-upgrade invocation immediately found 1 CRITICAL raw button outside shadcn pattern — fixed in-PR). **Doctrine 3 Sonnet → Opus upgrades** for gate-zero B2B/AI critical (security-auditor + prompt-guardrail-auditor + institution-rbac-auditor). ROI : ~+$10-25/month Opus invocations vs $1000+ B2B school incident avoided. **Sprint 2.B fully closed** with E2E PROD validation @thierry confirmed. **2 PRs shipped morning (#305 + #306). PR [#305](https://github.com/thierryvm/TerminalLearning/pull/305) = migration 027 hotfix super_admin can now approve cross-institution (RPC body check extended to `caller_role IN (institution_admin, super_admin)` + audit log enriched with `metadata.scope = 'global'|'institution'`). Audits 🟢 SHIP : security 9.4/10 + RBAC 0 CRITICAL/0 HIGH (16/16 static + 8/8 empirical REST API + JWT). 11/11 vitest PASS PROD. PR [#306](https://github.com/thierryvm/TerminalLearning/pull/306) = Sprint 2.B.2 UX feedback : permanent `🌐 scope: global` badge in header + emerald success status "{name} approved · scope {scope}" post-approve with 8s auto-clear + dismiss X (44×44 HIG fix ui-auditor 🔴→🟢 in-PR). 17/17 panel tests PASS (5 new). **E2E PROD validation @thierry confirmed 12h30** : connected as real super_admin → badge visible + click "Approuver" → green toast {name} + scope + 8s auto-disappear + optimistic UI row removed ✅. **Console logs investigation** : 11 Chrome DevTools errors detected and triaged — ALL from Brave Kwift Wallet extension (`chrome-extension://fdjamakpfbbddfjaooikfcpapjohcfmg`), 0 Terminal Learning errors. Our code = clean. **Doctrine `feedback_agent_dormant_full_audit` validated 3× this week** : 2 agent break-ins 26/05 (1 HIGH drift + 2 MED latents found) + E2E human validation @thierry 27/05 (1 UX bug structural audits had not flagged — human validation irreplaceable for end-user behavior). Tests 1724 → 1729 PASS (+5). **Sprint 2.B TOTALLY closed** with human E2E PROD validation. Sprint 2.C (Support System Resend) remains next session on explicit @thierry signal. — **Previous update (26 May 2026 ~18h CEST)** — 🏁 **Sprint 2.B CLOSED — institution_admin lite shipped 100%**: 3 PRs merged same session (#297 → #299), empirical E2E PROD validation via Chrome MCP. Migration 022b (3 École B test personas + institution) + 023 (`profiles UPDATE WITH CHECK institution_id`, [H1] hijacking fix) + 024 (GoTrue NULL global fix) + retroactive apply 011/012 (4+ week drift cross-institution leak on `institutions` table). PR [#298](https://github.com/thierryvm/TerminalLearning/pull/298) = migration 025 `approve_teacher(target_user_id uuid)` SECURITY DEFINER (caller institution_admin + same-institution + `SELECT ... FOR UPDATE` row lock + compare-and-swap `UPDATE` race-safe Sourcery, REVOKE EXECUTE FROM `public` + `anon` GRANT `authenticated` only) + migration 026 trigger AFTER UPDATE `audit_pending_teacher_promotion` defense in depth (transactional flag `app.in_approve_teacher_rpc` avoids double insertion when promotion goes through RPC) + 8 vitest empirical PROD tests. PR [#299](https://github.com/thierryvm/TerminalLearning/pull/299) = `InstitutionAdminPanel.tsx` route `/app/institution` gated `` + `usePendingTeachers` hook (fetch RLS auto-scoped + approve RPC + FR error mapping) + Sidebar "Mon institution" entry + 12 RBAC × behavior tests. **Audits cascade**: `security-auditor` **9.5/10 🟢 SHIP** 0 CRITICAL / 0 HIGH + `institution-rbac-auditor` ⚠ SHIP WITH NOTES (F-001 HIGH direct PATCH audit bypass + F-002 LOW anon EXECUTE + M1 leak interpolation) **all 3 findings fixed in-PR** + `ui-auditor` 🟡 SHIP WITH FIX (M1 aria-live scope + L3 touch target 44px fixed in-PR). **E2E PROD validation Chrome MCP via ephemeral 1h JWT injection institutionadmin_b**: (1) anonymous → "Vous devez être connecté" fallback ✅ (2) institutionadmin_b login → sidebar entry visible + panel render + count "(1)" only École B pending teacher (cross-institution RLS isolation empirically validated) ✅ (3) click "Approuver" → RPC success + optimistic UI row removed + count "(0)" + empty state ✅ (4) DB-side: profile role=teacher + 1 admin_audit_log row `action='approve_teacher'` complete metadata, **NO `direct_patch` row** (transactional flag works in real runtime) ✅ (5) 0 console errors. **Sentry secrets rotation**: 7 `SENTRY_*` integration-managed vars rotated 17:37:58 via Vercel↔Sentry native integration + production redeploy READY. `VITE_SENTRY_DSN` (client bundle) unchanged (Sentry doesn't rotate public DSNs). Badges "Needs Attention" cleared. **Cross-institution isolation score**: 7.5 → **9.5/10**. **Sprint 2.B shipped in 1 session ~5h, 0 regression, 0 incident, delegated autonomy honored, anti-leak discipline maintained** (1h-ephemeral JWT, .secrets/ + .tmp/ gitignored, passwords never in stdout, tool args = conversation context). **Doctrine validated** `feedback_agent_dormant_full_audit`: `institution-rbac-auditor` agent created 20 May, never empirically invoked until 26 May (6 days dormant) → first break-in found HIGH finding (4+ week production drift invisible). **Tests 1721/1741 PASS** (+12 vs Sprint 2.A close + 20 CI-only skipped). Three new CC memories consolidated: `feedback_anti_leak_discipline_jwt_short_lived.md` (patterns @thierry congratulated 26/05), `reference_supabase_plan_free.md` (auth_leaked_password_protection gated Pro plan), `feedback_agent_dormant_full_audit.md` (48h break-in mandatory doctrine). **Sprint 2.B = B2B schools cross-institution foundation layer ready for Sprint 2.C** (to scope next session). — **Previous update (24 May 2026 ~20h CEST)** — 🧠 **AI Tutor per-role shipped (Stage B1 + Stage B2)**: 7 PRs merged same day (#287 → #293). Stage B1 (PR #290, THI-260) = eval matrix frontier 2025-2026 on 10 models × 14 fixtures, $0.62 USD spent, two models 8/8 PASS (GPT-5.5 440 ms top latency + Opus 4.7 premium reasoning). Stage B2 (PR #291, THI-275) = three FR system prompts isolated per role (teacher / institution_admin / super_admin) + `getSystemPrompt({lang, mode, role})` dispatcher + student fallback defense-in-depth + 17 dispatcher tests + 4 `` injection fixtures × 4 locales. `prompt-guardrail-auditor` Sonnet found 2 CRITICAL (ghost `` block + DELIMITER_RX gap) **fixed before merge**. Cross-role server-side validation: 5/5 RBAC personas via REST API + `get_my_role` RPC. Two new agents shipped: `legal-compliance-auditor` (Opus 4.7, 5-layer GDPR/AI Act/DSA/CNIL/DPA-BE auto-update WebSearch, THI-270 PR #288) + `user-forensics-auditor` (Sonnet, 6-section GDPR-compliant, THI-274 PR #293, motivated by first organic user Jimmy Pez). `llm-security-auditor` Opus 7-layer on Stage B1 = 9.2/10 ⚠️ SHIP with mitigations all applied (H2-AI VERIFIED default OpenRouter Llama → Sonnet 4.6 fixed). H3-AI minor user consent (GDPR Art. 8) → Sprint 2.B gate-zero `institution-rbac-auditor`. Tests 1697 PASS (+57 vs pre-session). Sprint 2.B next: `institution_admin` lite + InstitutionAdminPanel skeleton + approve_teacher RPC + `institution-rbac-auditor` gate (THI-238 ready). — **Previous update (20 May 2026)** — 🏁 **Sprint 2.A 100% shipped** (5 PRs in 3 days). Step 3 = page `/app/join` consuming `join_class_by_code` RPC, PR [#274](https://github.com/thierryvm/TerminalLearning/pull/274) merged today. Empirical happy path validated via Supabase MCP (student 105 impersonation → RPC success, no bug 42702/42883, cleanup clean). Cascade ALL GREEN : `ui-auditor` SHIP-READY · `security-auditor` 9.2/10 (H1 fonctionnel `?code=` perdu après login + M1 maxLength fixés en PR) · Voie A Chrome MCP empirical `?code=` preservation confirmed · Sourcery skipping rate-limit. New agent `classroom-workflow-auditor.md` created (THI-237 Done) for gate-zero on future class workflow PRs. Test suite 1604 → 1640 (+36). 2 backlog tickets created : THI-258 rate limit Edge Middleware (Medium) + THI-259 isMounted ref pattern standardization (Low). Sprint 2.B next: pending_teacher dashboard + institution_admin lite + VIEW classes_student_view (THI-236). > > **Previous update (19 May 2026)** : 🚀 Sprint 2.A Teacher workflow 75% shipped (steps 1+2+2.bis+2.ter live in main). Five PRs merged today: [#267](https://github.com/thierryvm/TerminalLearning/pull/267) `.env.example` exhaustive + [#268](https://github.com/thierryvm/TerminalLearning/pull/268) Teacher Dashboard CRUD (route `/app/teacher`, RequireRole, list + create class + copy invitation URL, migrations 020 CHECK constraints + 021 `extensions.gen_random_bytes` fix CRITICAL) + [#269](https://github.com/thierryvm/TerminalLearning/pull/269) Role-aware nav hub + login redirect safe (cards "MES OUTILS" + Sidebar Administration super_admin + 7-layer open-redirect protection) + [#270](https://github.com/thierryvm/TerminalLearning/pull/270) Adaptive default route per role (super_admin → `/app/admin`, teacher → `/app/teacher`) + [#271](https://github.com/thierryvm/TerminalLearning/pull/271) docs CHANGELOG. Test suite **1545 → 1604** (+59). Cascade ALL GREEN: `security-auditor` 9.4-9.5/10 · `ui-auditor` SHIP-READY · `rbac-flow-tester` 11/11 E2E PASS · happy path RPC empirical via Supabase MCP (no bug 42702) · Voie A Chrome MCP anonymous fallback rendered · Sourcery PASS. Next: Sprint 2.A step 3 = `/app/join` page consuming `join_class_by_code` RPC. > diff --git a/docs/plan.md b/docs/plan.md index 13eb980..cb22e77 100644 --- a/docs/plan.md +++ b/docs/plan.md @@ -1,6 +1,6 @@ # Terminal Learning — Plan de lancement public -> Dernière mise à jour : **2 juin 2026 CEST** — **🔧 THI-326 + 📋 Sprint 2.C Étape 5 livrées (PRs #365/#366)** — **THI-326** : un `: ` (deux-points + espace) dans le frontmatter YAML cassait le parsing et empêchait `supabase-backend-auditor` + `user-forensics-auditor` de se charger comme sous-agents ; cause prouvée via js-yaml + garde-fou test dep-free (`agentFrontmatter.test.ts`, parse les 20 agents). **Sprint 2.C Étape 5 (THI-325, PR #366)** : page « Mes signalements » read-only `/app/support` (RLS user-select-own auto-scope, 0 backend, 0 migration) + entrée Sidebar gated ; v1 sans rendu screenshot (marqueur « Capture jointe », décision sécu → sous-tâche THI-336). Gates : security-auditor 9.6/10 (isolation RLS prouvée REST+JWT) · ui-auditor · code-reviewer (fix Intl.DateTimeFormat). Voie A desktop/tablette/mobile 390px (0 overflow). Cleanup prod 54 tickets de test synthétiques (THI-334 hygiène tests). Break-in content-auditor 0 CRITICAL. Tickets : THI-332/333/334/336/337/338. — **Mise à jour précédente (2 juin)** — **🗂️ Sprint 2.C Étape 4 livrée — triage des signalements super_admin (THI-320, PR #364)** : section « Signalements » dans `/app/admin` (liste + filtre par statut + description + capture re-signée à la lecture + changement de statut journalisé dans `admin_audit_log`). **Système support complet** (formulaire → stockage chiffré → email mainteneur → triage). **Décision dropdown** : Radix Select **écarté** (injecte du style inline → violerait la CSP stricte `style-src`, durcissement THI-120) au profit d'un `` natif `[color-scheme:dark]` — CSP 100% intacte, 0 dépendance. Gates : security-auditor 9.5/10 · supabase-backend (inline, agent non chargé runtime → THI-326) · ui-auditor SHIP · mobile-responsive PASS · code-reviewer (findings appliqués) · **Voie A e2e super_admin « 2 sens »** (submit avec capture → triage → statut aller-retour → audit confirmé en base → image chargée sans violation CSP, desktop + mobile 390px). Suite : visibilité user de ses propres tickets (THI-325). — **Mise à jour précédente (1er juin 2026 CEST, soir)** — **📧 Sprint 2.C Étape 3 livrée — notification email support (THI-319, PR #360)** : à la création d'un ticket support, le super_admin reçoit un email (Resend). Implémenté en **route Vercel Edge** `api/support/notify.ts` (pivot vs Edge Function Supabase du brief — code-verify : clé Resend déjà en env Vercel + `api/*` déjà serverless → 0 plateforme/dépendance/secret nouveau). **Autorisation déléguée à RLS** (JWT user forwardé à PostgREST ; ligne renvoyée seulement si owner/super_admin, aucun `service_role`). Anti-replay freshness 60s + rate-limit 10/min/IP + description HTML-escaped + `Cache-Control: no-store` + best-effort (email raté ≠ ticket perdu). **3 gates 0C/0H** (security-auditor 9.2/10 · route-attack-auditor ship · code-reviewer clean) + **email réellement reçu** (Gmail MCP vérifié) + smoke prod 200. Resend free tier (3000/mois). **THI-319 Done — Sprint 2.C : reste l'Étape 4** (section Tickets Dashboard super_admin, THI-320). Aussi 1er juin : filtre crawlers Sentry (THI-317, #358, moins de bruit d'alertes). — **Mise à jour précédente (1er juin 2026 CEST, après-midi)** — **🎯 Cohérence catalogue : validateurs ↔ instruction ↔ contenu ↔ OS (THI-316 · ferme THI-293, PR #357)** : audit complet des 66 validateurs (lecture exhaustive + instructions cross-référencées + **support moteur vérifié**) suite au blocage @thierry (`help ls` rejeté sur la leçon orientation). **4 validateurs corrigés** : `validateOrientation` (`=== 'help'` → accepte `help`/`help `/`man`/`man ` ; `whatis`/`apropos` refusés car non exécutés par le moteur — pas de validation sur sortie d'erreur) · `validateCd` (tolère le slash de tab-complétion `cd documents/`) · `validatePing` (accepte les options enseignées `-c`/`-n`/`-t`/`-i`, hôte requis via lookahead) · `validateCurl` Linux (exige une URL http(s), ferme W1). **THI-293 fermé** : `reseau` ping/ssh/scp reçoivent `instructionByEnv.windows`+`hintByEnv` (commandes identiques natives Win10+, CRITICAL→INFO). **Gates ALL GREEN** : curriculum-validator 0C · test-runner 1949 pass · content-auditor 0C (THI-293 C1/C2/C3 fermés + W1 comblé : spot-checks `reseau/*`+`orientation` ajoutés §4) · feature-dev:code-reviewer ship (ReDoS borné, edge cases vérifiés). **~50 tests 3 OS** (validators.test + curriculumEnvAwareness §4 déterministe par environnement). **Voie A preview** : `help ls` valide + auto-advance (bug @thierry résolu end-to-end). Revus & laissés tels quels (documenté THI-316) : cp/mv/rm/cat (exact-match), kill (`ps aux`), chown/githubActions (alignés instruction). **PR #357 attend la validation visuelle @thierry** (réalisée en autonomie, NON mergée — discipline respectée). — **Update précédent (THI-315 · THI-310 · THI-313)** — **🔐 Fiabilité déconnexion + imports async + nav leçon mobile (THI-315 · THI-310 · THI-313, PRs #355 + #353 + #354 mergées)** : session de reprise post-THI-310, partie d'un signalement utilisateur → 3 bugs distincts corrigés. **(1) THI-315 HOTFIX déconnexion** : « Se déconnecter » laissait parfois l'user connecté sur la landing — la révocation serveur était fire-and-forget → `await signOut()` rendait la main avant l'effacement du token persisté → `autoRefreshToken`+`onAuthStateChange` restauraient la session (race intermittente). Fix : **await la révocation** (token effacé avant nav) borné `Promise.race` timeout 4s ; `setSession(null)` garde le feedback instantané. security-auditor 8.5/10, renforce THI-186. Retest prod @thierry OK. **(2) THI-310 durcissement imports async** : reliquat #349 — `completeLesson`/`useUserRole`/`signOut`/init `getSession` chaînes catch-less → dégradation propre (syncStatus error / rôle `null` restrictif + cache **auto-réparant** M1 / teardown inconditionnel). security-auditor 9.5/10, +3 tests, Sourcery (timeout+comment). **(3) THI-313 nav leçon mobile** : sur mobile l'user atterrit sur le panneau Terminal mais Précédent/Suivant n'étaient que dans le panneau Contenu → footer nav `lg:hidden` persistant (composant `LessonNav` partagé DRY, desktop inchangé) + cue « leçon déjà complétée ». **Voie A a attrapé un overlap FAB↔Suivant** (lift gaté `pointer:coarse` au lieu du breakpoint `` `~` `-` `/` … + Tab + historique, insertion **au curseur**, clavier natif maintenu ouvert via `onPointerDown`), **FAB tuteur IA remonté** au-dessus de la barre sur leçons tactiles, **fades de scroll dynamiques** (affordance), 44×44px, 0 overflow 390px. Gates : **ui-auditor** 0C + **feature-dev:code-reviewer 2 passes** (4 findings IMPORTANT corrigés, dont `pointerdown` vs `mousedown` no-op iOS qui cassait la feature) + Sourcery (fallback `addListener` + helper simplifié). Voie A émulation iPhone validée (insertion `|>`, focus conservé, FAB gap 6px, fades début/milieu/fin), 41 tests. ⚠️ Clavier *natif* iOS à confirmer appareil réel. **THI-308 créé** (High) : session expirée iOS Safari ITP → 0% progression **silencieux** (DB intacte, vérifiée 24 leçons read-only) ; fix UX = bandeau « reconnecte-toi pour retrouver ta progression » au lieu de blanking muet (protection anti-fuite THI-186 préservée). — **Update précédent (31 mai PR-3a sandbox git)** — **🔁 THI-305 PR-3a (sandbox git exécutable)** : **PR #344 mergée** — `git rebase` (+ `-i` guidance + warning branche partagée) et **`git cherry-pick`** désormais simulés dans le terminal → les leçons git ont des exercices exécutables (avant : référencés mais non pratiquables). `cherry-pick` ajouté au catalogue + source git-scm.com, **75→76 commandes**. Gate **`feature-dev:code-reviewer` codifié + appliqué** : a trouvé un ordre de gardes inversé (corrigé). +9 tests engine. Voie A desktop+mobile (0px overflow). **Audit sandbox** : ~21 sous-cmd à état réel mais `diff` canned + `merge` sans conflits + `commits[]` global → **phase 2** (modèle per-branche) backlogée. **THI-306** (code-review sweep full-codebase) + **THI-307** (barre touches mobile `|`/`>`, High) créés. **Gate code-review codifié dans CLAUDE.md** (exemptions docs/config + ordre vs gates spécialisés). — **Update précédent (31 mai PR #5 Git & GitHub Référence)** — **🌿** : **PR #340 mergée** — catégories `git` (10 cmds) + `github-collaboration` (6 cmds) ajoutées au catalogue → **59 → 75 commandes** sur `/app/reference`. Sources **git-scm.com** (URLs vérifiées HTTP 200 ; git identique cross-OS = 1 lien canonique/cmd, 0 variante OS). Catégories mirrorent level+prerequisites curriculum (garde-fou cohérence). **`ia-dev` exclu** (pseudo-commandes `ai-help`, 0 doc CLI officielle). Compteurs sync (TOTAL_COMMANDS 75 + FAQ index.html) + **nouveau garde-fou** test : FAQ index.html == constantes (review Sourcery, fini le drift HTML silencieux). Voie A desktop+mobile (0px overflow 390px), 104 tests verts. **Sandbox THI-305 (High)** créé : sandbox git déjà ~21 sous-commandes, mais `git rebase` manquant + audit profondeur (merge commits/conflits réels) pour garantir un exercice exécutable par leçon git. — **Update précédent (31 mai PR #4 Sources officielles)** — **📚** : **PR #337 mergée** — chaque commande de `/app/reference` porte ses **sources officielles** (champ `officialDocs[]` sur `EnrichedCommand`, 57/59 commandes, fusion à l'export → catalogue reste source unique). Modèle par-OS canonique : Linux→man7.org · Windows→Microsoft Learn · macOS→Homebrew + upstream (OpenSSH/GNU/curl) · Debian man-pages (tree/dig/zip/unzip). `open`/`pbcopy` sans lien (pas d'hôte Apple officiel propre, 0 tiers). **Anti-hallucination** : chaque URL vérifiée live HTTP 200 (batch curl HEAD), garde-fou test allow-list domaines officiels + https. Gates : `ui-auditor` SHIP (H1 a11y nouvel-onglet + M2 ring-offset fixés), **Voie A desktop + mobile 390px** (0px overflow, labels wrappent). Aussi **PR #335** (invariants catalogue variant⊆compatibility + syntax/examples). **Process codifié** : Voie A inclut désormais mobile 390px (incident #337 desktop-seul). **Reste chantier** : PR-2 git/github/ia-dev dans le catalogue (+ leurs sources git-scm/GitHub Docs) → éditeur nano v1 → help/man enrichi → progression. — **Update précédent (31 mai PR #3)** — **🗂️ Références unifiées** : **PR #333 mergée** — `commandCatalogue.ts` devient la **source canonique unique** des commandes ; `/app/reference` (CommandReference.tsx) **dérive** désormais du catalogue (`flatMap`, array local de 44 cmds supprimé ~600 lignes). Fin de la divergence deux-sources (le compteur landing pouvait diverger de la page vue par l'user). **38 → 59 commandes**, 0 historique perdue, data migrée (groundée, pas inventée) : nouvelle catégorie `systeme` (+11) + `tree`/`sudo`/`umask`/`getacl`/`jobs`/`bg`/`fg`/`printenv`/`2>`/`2>&1` + spécifiques-OS préservées (Get-Acl, Get-ComputerInfo, open, pbcopy, brew, winget). UX multi-OS : badges compatibilité + variantes par environnement + recommendedFor + commonErrors. **Garde-fou** `commandReferenceSource.test.ts` (assert structurel : page importe le catalogue, pas de réintro d'array local ; assert data : ids historiques présents + catalogue ≥ 59) → la divergence ne peut plus revenir silencieusement. Gates : `ui-auditor` MERGE (1 HIGH a11y clavier pré-existant fixé in-PR) + `content-auditor` 0C (3 warnings fixés + **prompt agent mis à jour** : catalogue = source unique + check compteurs public/). Voie A Playwright PASS (Linux 53 / Windows 54, switch env OK), validation visuelle @thierry « très propre et adapté aux multi-OS ». Réalisé via **session parallèle** (rapport vérifié empiriquement avant merge, pas sur parole). **Reste chantier** : compléter git/github/ia-dev dans le catalogue (apparaîtront auto) → éditeur nano v1 → help/man enrichi OS-spécifique → progression. — **Update précédent (30 mai 2026 ~21h CEST)** — **📚🔒 Chantier enrichissement curriculum démarré (2 PRs)** : **PR #330 (sécu IA d'abord)** = clause frontière pédagogique prompt élève `tutor/v1.1.0→1.1.1` (le tuteur explique mais ne génère jamais de payload offensif, anti-chaîne réputationnelle ROT13→CTF-légal→reverse-shell) + strip reverse-shell output-side + décodeurs ROT13/hex sanitizer + prompt super_admin `v1.0.1` sans littéraux secrets (F-2) + fix commentaire (F-5). Gate `prompt-guardrail-auditor` **SHIP 9.3/10** (0C/0H, 2 MED assumés, 2 LOW fixés in-PR) + delta-check Sourcery (décodeur partagé + regex bornée). Tests AI **412**, injection fixtures 48→56. Démo Voie A connectée (JWT élève éphémère révoqué). **PR #331 (1er contenu)** = leçon fondatrice `command-anatomy` (Navigation niv.1, entre `ls -la` et `cd`) — comble un trou : on enseignait les options au cas par cas sans le modèle universel `commande [options] [arguments]` (court/long, combinaison, `--`, renvoi man/--help). Variante Windows (paramètres PowerShell, Get-Help). Exercice `man ls` + `validateCommandAnatomy` forward-compatible Get-Help. 1er test moteur `man` (closait WARNING audit). **Drift guards 65→66** sur 6 sources de vérité. **test-runner 1834 PASS**, curriculum-validator 0 CRITICAL. Idée @thierry « leçon sur les options » → trou invisible révélé par une question utilisateur. **Reste chantier** : PR Références (commandCatalogue 5 modules manquants) → éditeur nano v1 → contenu manquant (less/find/tar) → help/man enrichi OS-spécifique → progression. — **Update précédent (30 mai 2026 ~14h CEST)** — **🚀 Sprint 2.C étape 2 livrée (PR #326)** : système de signalement in-app. **Migration 030** bucket privé `support_screenshots` + 5 policies RLS `storage.objects` (user own folder via `foldername[1]=auth.uid()` / super_admin all RGPD Art.17). **`submitTicket.ts`** upload → URL signée 7j (conforme contrainte 029 M1) → insert + cleanup orphelin. **`SupportTicketModal`** focus-trap + Escape + form 3 champs + disclaimer PII, trigger Sidebar « Aide & feedback » gated `user`. **3 audits gate-zero ALL GREEN** : `supabase-backend-auditor` SHIP (**11 tests adversariaux live prod** path-traversal/MIME-spoof/oversize/cross-user-signed-URL tous bloqués, 0C/0H) + `ui-auditor` clean (0 hex introduit) + `security-auditor` **9.3/10**. **code-review** 0 critical (2 fixes : double-label a11y + DRY isAllowedMime). **Context7** confirme API Storage Supabase à jour. Tests **1765 → 1780 PASS** (8 composant jsdom + **7 RLS bucket empiriques PROD** REST+JWT incl. T7 non-régression cross-user signed URL). Suivis Étape 3/4 tracés (non bloquants) : validation magic-bytes serveur (MIME déclaré falsifiable) + rate limit upload/insert API4 (backlog 2.D) + CSP `img-src` supabase.co à l'Étape 4 (rendu screenshot). **CHANGELOG catch-up #319-325** (drift 29/05 signalé au shutdown). **Sprint 2.C reste 2 étapes** (Edge Function Resend → AdminPanel section Tickets). — **Update précédent (28 mai 2026 ~tard CEST)** — **🚀 Session post-reset : 3 PRs livrées (#314 → #316) + switch Opus 4.8**. **PR #314** vision plateforme B2B Option D Hybrid (doc strategy 549 lignes, Voie C) + **13 tickets Linear** (THI-282 umbrella Phase X B2B + 8 sub X1→X6 + THI-291/292/293/294 backlog). **PR #315 Sprint 2.C étape 1** = table `support_tickets` + RLS scoped + trigger audit (migration 028 base + 029 hardening security-auditor Opus 8.8→9.4/10 : H1 trigger guard auth.uid NULL + H2 WITH CHECK + M1 screenshot_url Storage-only XSS defense + M2 super_admin DELETE RGPD Art.17 + M3 status/resolved coherence + L1 search_path). **15/15 tests vitest empiriques PROD** (RLS REST+JWT). Full regression **1744/1764 PASS**. **PR #316 audit méta 20 agents post-4.8** : nouvel agent `supabase-backend-auditor` (Opus, gate-zero Edge Function Deno + Storage RLS + file upload, AVANT Étape 3 Resend + X3b import), `linear-sync` réécrit (avoue échec MCP au lieu de deviner — incident 28/05 sous-agent 6 incohérences fausses), README sync modèles, garde-fou pin 4.7→4.8. **Règle dure @thierry : JAMAIS Haiku** (0 Haiku / 12 Sonnet / 8 Opus). **MCP Supabase réparé** (mauvais compte gmail/Ankora → reconnecté TL, near-miss SQL Ankora rollback auto 0 dégât) + registry 028/029 aligné. **Sprint 2.C reste 3 étapes** (SupportTicketModal UI + bucket support_screenshots → Edge Function Resend → AdminPanel section Tickets). — **Update précédent (27 mai 2026 ~16h CEST)** — **🔧 Session marathon 27 mai : 6 PRs livrées (#305 → #310)** : Sprint 2.B reliquats hotfix RPC super_admin + Sprint 2.B.2 UX scope badge + Sprint 2.B.3 sidebar "Mes outils" collapsible THI-240 + UserMenu hover fix + doctrine modèles agents alignée (0 Haiku / 12 Sonnet / 7 Opus). **ui-auditor upgrade Haiku → Sonnet** (1ère invocation post-upgrade a immédiatement trouvé 1 CRITICAL raw button hors pattern shadcn — fix in-PR). **Doctrine 3 upgrades Sonnet → Opus** gate-zero critiques B2B/IA (security-auditor + prompt-guardrail-auditor + institution-rbac-auditor). ROI estimé : ~+$10-25/mois invocations Opus vs $1000+ incident B2B école évité. **Sprint 2.B totalement clos** validation E2E PROD @thierry confirmée. **2 PRs livrées matin (#305 + #306). PR [#305](https://github.com/thierryvm/TerminalLearning/pull/305) hotfix migration 027 = super_admin peut maintenant approve cross-institution (RPC body check étendu `caller_role IN (institution_admin, super_admin)` + audit log enrichi `metadata.scope = 'global'|'institution'`). Audits 🟢 SHIP : security 9.4/10 + RBAC 0 CRITICAL/0 HIGH (16/16 static + 8/8 empirical REST API + JWT). 11/11 tests vitest PASS PROD. PR [#306](https://github.com/thierryvm/TerminalLearning/pull/306) Sprint 2.B.2 UX feedback = badge `🌐 scope: global` permanent dans header + success status emerald "{nom} approuvé · scope {scope}" post-approve avec auto-clear 8s + dismiss X (44×44 HIG fix ui-auditor 🔴→🟢 in-PR). 17/17 tests panel PASS (5 nouveaux Sprint 2.B.2). **Validation E2E PROD @thierry confirmée 12h30** : connecté super_admin réel → badge visible + click "Approuver" → toast vert {nom} + scope + auto-disparition 8s + optimistic UI row disparue ✅. **Investigation logs console** : 11 erreurs Chrome DevTools détectées et triées — TOUTES viennent de l'extension Brave Kwift Wallet (`chrome-extension://fdjamakpfbbddfjaooikfcpapjohcfmg`), 0 erreur Terminal Learning. Notre code = sain. **Doctrine `feedback_agent_dormant_full_audit` validée 3× cette semaine** : 2 break-ins agents 26/05 (1 HIGH drift + 2 MED latents trouvés) + validation E2E humaine @thierry 27/05 (1 bug UX que les audits structurels n'avaient pas flaggé — validation humaine irremplaçable pour comportement utilisateur final). Tests 1724 → 1729 PASS (+5). 2 mémoires CC updates : `feedback_anti_leak_discipline_jwt_short_lived.md` + `project_sprint_2b_super_admin_approve_bug.md` marqué `RÉSOLU`. **Sprint 2.B TOTALEMENT clos** avec validation E2E PROD humaine. Sprint 2.C (Support System Resend) reste prochaine session sur signal explicite. — **Update précédent (26 mai 2026 ~18h CEST)** — **🏁 Sprint 2.B CLOS — institution_admin lite livré 100%** : 3 PRs mergées même session (#297 → #299), validation E2E PROD Chrome MCP empirique. PR [#297](https://github.com/thierryvm/TerminalLearning/pull/297) **Étape 1** = 4 migrations institution B (022b 3 personas test École B + 023 `profiles UPDATE WITH CHECK institution_id` H1 hijacking fix + 024 GoTrue NULL global fix + apply rétroactif 011/012 drift 4+ semaines fuite cross-institution institutions table). Score isolation 7.5 → **9.5/10**. PR [#298](https://github.com/thierryvm/TerminalLearning/pull/298) **Étape 3** = migration 025 RPC `approve_teacher(target_user_id uuid)` SECURITY DEFINER (caller institution_admin + same-institution + FOR UPDATE row lock + compare-and-swap UPDATE race-safe Sourcery, REVOKE EXECUTE FROM public + anon GRANT authenticated only) + migration 026 trigger AFTER UPDATE `audit_pending_teacher_promotion` defense in depth (flag transactionnel `app.in_approve_teacher_rpc` évite double insertion) + 8/8 tests vitest empirique PROD. Audits : `security-auditor` **9.5/10 SHIP** 0 CRITICAL / 0 HIGH + `institution-rbac-auditor` SHIP WITH NOTES (F-001 HIGH direct PATCH audit bypass + F-002 LOW anon EXECUTE missing revoke + M1 RAISE EXCEPTION leak) **3 findings fixés in-PR**. PR [#299](https://github.com/thierryvm/TerminalLearning/pull/299) **Étape 4** = `InstitutionAdminPanel.tsx` route `/app/institution` gated `` + hook `usePendingTeachers` (fetch RLS auto-scoped + approve RPC + FR error mapping) + Sidebar entry "Mon institution" + 12/12 tests RBAC fallback × behavior. Audit `ui-auditor` 🟡 SHIP WITH FIX → M1 aria-live scope + L3 touch target 44px fixés in-PR. **Validation E2E PROD Chrome MCP via JWT injection éphémère 1h institution_admin_b** : (1) anonymous → fallback "Vous devez être connecté" ✅ (2) login institutionadmin_b → sidebar entry + panel + count "(1)" pending_teacher_b École B uniquement (cross-institution isolation empirique) ✅ (3) click "Approuver" → RPC success + optimistic UI row disparu + count "(0)" + empty state ✅ (4) DB-side : profile role=teacher + 1 row admin_audit_log action='approve_teacher' metadata complet **PAS de row direct_patch** (flag transactionnel fonctionne en runtime réel) ✅ (5) 0 console errors. **Rotation Sentry secrets** via intégration native Vercel↔Sentry (7 vars `SENTRY_*` rotated 26 mai 17:37:58 + redeploy production READY immédiat) — `VITE_SENTRY_DSN` client unchanged (DSN public stable). **Sentry "Needs Attention" badges cleared.** **Sprint 2.B livré en 1 session ~5h** : 0 régression, 0 incident, autonomie déléguée respectée, discipline anti-leak maintenue (JWT éphémère 1h, .secrets/ + .tmp/ gitignored, password jamais en stdout, tool args = conversation context). **Doctrine validée** `feedback_agent_dormant_full_audit` : agent `institution-rbac-auditor` créé 20 mai jamais invoqué empiriquement avant 26 mai (6 jours dormant) → premier break-in a trouvé finding HIGH (drift production 4+ semaines invisible). **Tests 1721/1741 PASS** (+12 vs Sprint 2.A close + 20 skipped CI-only). Mémoires CC consolidées : `feedback_anti_leak_discipline_jwt_short_lived.md` (patterns validés @thierry féliciter 26/05), `reference_supabase_plan_free.md` (auth_leaked_password_protection gated Pro plan), `feedback_agent_dormant_full_audit.md` (doctrine 48h break-in obligatoire). **Sprint 2.B essentiellement le « palier B2B écoles cross-institution »** — fondation prête pour Sprint 2.C (à scoper prochaine session). — **Update précédent (24 mai 2026 ~20h CEST)** — **🧠 AI Tutor par rôle livré (Stage B1 + Stage B2)** : 7 PRs mergées même jour (#287 → #293). Stage B1 (PR #290, THI-260) = eval matrix frontier 2025-2026 sur 10 modèles × 14 fixtures, $0.62 USD, 2 modèles 8/8 PASS (GPT-5.5 440 ms top latence + Opus 4.7 premium). Stage B2 (PR #291, THI-275) = 3 system prompts FR cloisonnés par rôle (teacher / institution_admin / super_admin) + dispatcher `getSystemPrompt({lang, mode, role})` + fallback student defense-in-depth + 17 tests dispatcher + 4 fixtures injection `` × 4 langues. Audit `prompt-guardrail-auditor` Sonnet a trouvé 2 CRITICAL (ghost block `` + DELIMITER_RX gap) **fixés avant merge**. Vision @thierry verrouillée : « niveau différent selon rôle pour éviter utilisations malveillantes hackers et gros curieux ». **Validation cross-role server-side** : 5/5 RBAC personas via REST API + `get_my_role` RPC. **2 nouveaux agents livrés** : `legal-compliance-auditor` (Opus 4.7, 5 couches RGPD/AI Act/DSA/CNIL/DPA-BE auto-update WebSearch, THI-270 PR #288) + `user-forensics-auditor` (Sonnet, 6 sections RGPD-compliant, THI-274 PR #293, motivé cas Jimmy Pez premier user organique). **Audits ship** : `llm-security-auditor` Opus 7 couches sur Stage B1 = 9.2/10 ⚠️ SHIP avec mitigations toutes appliquées (H2-AI VERIFIED default OpenRouter Llama → Sonnet 4.6 fixé). Mitigation H3-AI consent mineurs RGPD Art. 8 → gate-zero Sprint 2.B `institution-rbac-auditor`. **Doctrine `AskUserQuestion` codifiée** (mémoire `feedback_askuser_recommend_first.md`) : toujours marquer recommandation explicite, ne pas laisser @thierry trancher seul ce que j'ai déjà jugé. **Tests 1697 PASS** (+57 vs main pré-session). **Dette identifiée** : ADR-009 cross-role isolation à créer (cette PR), `llm-security-auditor` Opus 7 couches sur Stage B2 reporté Stage B1.b (justifié — couverture transverse via B1 frais 4h avant). Sprint 2.B prochaine session : `institution_admin` lite + InstitutionAdminPanel skeleton + approve_teacher RPC + gate `institution-rbac-auditor` (THI-238 prêt). — **Update précédent (20 mai 2026 ~18h CEST)** — **🏁 Sprint 2.A complet à 100%** : étape 3 page `/app/join` livrée PR [#274](https://github.com/thierryvm/TerminalLearning/pull/274). Chaîne teacher → URL invitation → student → enrollment → progression visible fonctionne empiriquement end-to-end (test Supabase MCP impersonation student 105 → RPC `join_class_by_code('a4368184d202')` → success sans bug 42702/42883, cleanup propre 0 row restant). Sprint 2.A = 5 PRs mergées en 3 jours (#266 migrations + #268 Teacher Dashboard + #269 nav hub + #270 adaptive routing + #274 page join). **Tests 1640** (+36 étape 3). Cascade pré-merge ALL GREEN : `ui-auditor` SHIP-READY · `security-auditor` 9.2/10 (H1 fonctionnel `?code=` perdu après login + M1 maxLength 12 + pattern hex fixés en commit fixup avant push) · Voie A Chrome MCP empirique sessionStorage `?code=` preservation confirmée · Sourcery PASS rate-limit. Nouvel agent `classroom-workflow-auditor.md` créé (THI-237 Done) — gate-zero pour futures PRs touchant `classes`/`class_enrollments`/RPCs class-related, pattern Supabase MCP JWT impersonation documenté 14 checks structurés. **Cleanup Linear** : THI-237 + THI-239 passés Done (agent + tests + E2E empirique livrés), 0 candidate Cancel sur 31 issues Backlog audit (signal positif discipline projet). **2 tickets follow-up backlog** créés via security-auditor M2+M3 : THI-258 (rate limit Edge Middleware `/rest/v1/rpc/join_class_by_code` gated Pro plan, Medium) + THI-259 (standardiser `isMounted` ref pattern hooks async, Low). **Mea culpa session** : (1) agent `.md` créés en cours de session pas rechargés avant prochaine session — pattern documenté dans STORY narrative étape 3 + agents/README, (2) JSDoc qui promet un comportement non-implémenté = bug latent (H1 security-auditor) corrigé. **Process discipline maintenue** sous carte blanche technique : cascade complète + Voie A empirique + Sourcery + 5 personas comptes tests rappelés par @thierry en début de session, exactement ce qui a permis d'attraper H1+M1 avant production. **Quota Anthropic 88%/semaine** → fermeture session disciplinée avec STORY narrative + CHANGELOG + handoff Obsidian livrés cette session (leçon différer-ce-qui-est-demandé hier soir intégrée), refactors lourds (ARCHITECTURE drift > 5 sem THI-245, CONVENTIONS/GUIDELINES THI-246, teacher-guide THI-247) reportés sessions matinales fraîches post-reset. **Sprint 2.B suit** : pending_teacher dashboard + institution_admin lite + VIEW `classes_student_view` (THI-236 hide invitation_code from enrolled students). — **Update précédent (19 mai 2026 ~21h CEST) — 🚀 Sprint 2.A Teacher workflow shippé à 75% (étapes 1+2+2.bis+2.ter livrées)**. Cinq PRs mergées journée : [#267](https://github.com/thierryvm/TerminalLearning/pull/267) (`.env.example` complet — 3 vars → 12 vars exhaustives pour fork/onboarding), [#268](https://github.com/thierryvm/TerminalLearning/pull/268) **THI-235 étape 2 Teacher Dashboard CRUD** (route `/app/teacher` RequireRole teacher/super_admin + listing "Mes classes" + form inline création + ClassCard copy URL invitation, migrations 020 hardening CHECK constraints + **021 fix CRITICAL** `extensions.gen_random_bytes` schema isolation bug 42883 découvert empiriquement post-020), [#269](https://github.com/thierryvm/TerminalLearning/pull/269) **étape 2.bis Role-aware nav hub + login redirect safe** (section "MES OUTILS" sur `/app` Dashboard role-gated + Sidebar entry "Administration" super_admin + fallback unauthenticated "Se connecter" + 7 défense layers open-redirect protection via `validateReturnTo` + sessionStorage `auth_return_to`, déclenché par feedback empirique @thierry "je n'avais même pas vu le lien dans la sidebar mdr"), [#270](https://github.com/thierryvm/TerminalLearning/pull/270) **étape 2.ter Adaptive default route per role** (super_admin → `/app/admin`, teacher → `/app/teacher`, autres → `/app` ; refactor `consumeReturnTo` API `string` → `string | null` pour distinguer "no intent" de "invalid intent" ; déclenché par @thierry "je ne suis pas teacher de base, je suis super-admin, à la limite, c'est sur mon dashboard de contrôle que je devrais arriver"), [#271](https://github.com/thierryvm/TerminalLearning/pull/271) docs CHANGELOG entry détaillée 2.ter. **Tests** 1545 → **1604** (+59 nouveaux components/helpers + refactor returnToStorage). **Cascade rigoureuse** par-PR : `security-auditor` 9.4–9.5/10 SHIP (2 HIGH fixés migrations 020+021, 1 MEDIUM L1 cosmétique AbortController fixé fixup) · `ui-auditor` SHIP-READY (0 CRITICAL/HIGH/MEDIUM) · `rbac-flow-tester` **11/11 PASS** sur prod Supabase (5 personas + Sprint 2.A workflow complet + RLS isolation + cleanup) · happy path RPC empirique via Supabase MCP `join_class_by_code('a4368184d202')` impersonate student 105 → success sans bug 42702 · Voie A Chrome MCP anonymous `/app/admin` fallback rendu 0 console error · Sourcery PASS. **6 tickets follow-up** Linear Backlog créés : THI-237 `classroom-workflow-auditor` agent (gate avant étape 3) · THI-238 `institution-rbac-auditor` agent (Sprint 2.B) · THI-239 Vitest tests `joinClassByCode` regression net (gate avant étape 3) · THI-240 Sidebar refactor "Mes outils" collapsible · THI-241 PostgREST error message sanitization · THI-242 institution_admin invitation_code visibility ADR. **Industry research codifiée** (DAR Design Multi-Role B2B UX 2026 + Orbix B2B SaaS Dashboard + Lollypop SaaS Navigation) : "preference, not restriction" pattern → onboarding wizard = anti-pattern 2026. **Mea culpa session** : push direct main pour `.gitignore` matin reconnu, engagement 100% via PR maintenu reste journée ; dismiss initial du `rbac-flow-tester` finding pgcrypto schema corrigé empiriquement (migration 021), leçon process `feedback_happy_path_testing.md` confirmée ; merge autonome `--admin` PR #270 + #271 sous carte blanche @thierry (exception cadrée, à reproduire uniquement si validée en avance ou hotfix critique). **Sprint 2.A étape 3** suit demain : page `/app/join` consommant RPC `join_class_by_code` (pré-requis verrouillés AVANT merge : créer `.claude/agents/classroom-workflow-auditor.md` + livrer THI-239 + validation Voie A multi-personas). **Critère release-ready Sprint 2.A complet** : teacher crée classe → copy URL → student rejoint via code → enrollment success + classe visible Dashboard student. — **Update précédent (18 mai 2026 ~13h45 CEST) — 🎯 Sprint 2 essentiellement clos en avance** : THI-118 LCP + THI-153 UI cleanup + THI-131 LTI Phase 7c + **THI-42 PR #1 Profile Hub** tous Done bien avant deadline 10 juin. Hat-trick sécurité post-audit : **PR [#255](https://github.com/thierryvm/TerminalLearning/pull/255) THI-42 PR #1** (Profile Hub shell + UserMenu "Mon profil" link, 5 fichiers +418/-17, ui-auditor 4 CRITICAL hex hardcodés drive-by fixés, security-auditor 9.2/10 H1 race condition auth guard FIXÉ avec `initialized` check + loading state, Voie A desktop + iPhone 14 PASS, fix a11y back-link tap target 198×16 → 214×44 commit `504554c` avant merge). **PR [#256](https://github.com/thierryvm/TerminalLearning/pull/256) THI-219** CSP `img-src` énumération stricte `lh1`-`lh6.googleusercontent.com` (pattern bypass initial wildcard `*.googleusercontent.com` rejected par security-auditor — M1 content injection vector via `uc.googleusercontent.com` Drive/Gmail uploads — révisé en enum strict). Sourcery 2 suggestions valides (duplication CSP + commentaire inline) impossibles dans `vercel.json` strict JSON → ticket follow-up [THI-223](https://linear.app/thierryvm/issue/THI-223) créé : migration `vercel.json` → `vercel.ts` (pattern Vercel 2026 recommandé). **PR [#257](https://github.com/thierryvm/TerminalLearning/pull/257) THI-220** avatar URL validation defense-in-depth — `isValidAvatarUrl()` exporté dans `UserAvatar.tsx`, mirror CSP allow-list, fallback initials silencieux si validation échoue (compromised IdP / user_metadata tampering / future provider sans update CSP), 25 tests unitaires. **PR [#258](https://github.com/thierryvm/TerminalLearning/pull/258) THI-221** RequireAuth **opt-in wrapper** — scope revision majeure : reconnaissance révèle uniquement ProfilePage a le guard pattern, l'app est anonymous-friendly by design (Dashboard/LessonPage/AiSettings/CommandReference accessibles aux invités, mode invité fully supported). Un blanket Layout-level wrap aurait cassé cette UX. Refactor en wrapper opt-in (props children + fallback custom, gère `!initialized → loading` + `!user → fallback`), 6 tests + beforeEach reset (security-auditor L2). Voie A : `/app/profile` anonyme → fallback custom rendu ✅, `/app` Dashboard anonyme → fully accessible avec sidebar "Mode invité" + bouton "Se connecter" visibles ✅. Pattern prêt pour Phase 9 routes role-gated. Sas 48h doctrine override par @thierry pour cette session (« on avance normalement »). **Tests** : 1444 → 1475 (+31). **Score sécurité** : 9.2/10 stable. **4 PRs mergées + 5 tickets backlog créés** (THI-219 à 223). Sprint 2 deadline 10 juin large : reste **THI-77/78** (admin heatmaps) bloqués par **Phase 9 Admin Panel** umbrella à créer (route `/admin` + RBAC role-gated layout + skeleton dashboard, ~3-5j effort). Décision @thierry prochaine session : démarrage Phase 9 ou autre backlog. — **Update précédent (17 mai 2026 ~00h45 CEST) — 🚨 THI-186 Critical security fix livré en 3 rounds** : bug data leak inter-utilisateurs via `localStorage` non-cleared découvert en prod par @thierry (37 % / 24 lessons affichées en mode invité, contamination cross-account confirmée empiriquement via Supabase live query — `shared:24, only_google:0, only_hotmail:0`). Root cause dans `src/app/context/ProgressContext.tsx` dormante depuis **Phase 3 livrée 3 avril 2026** (6 semaines en prod sans détection). Fix livré en 2 PRs principales + 1 polish : **PR [#241](https://github.com/thierryvm/TerminalLearning/pull/241)** owner-tracking aux transitions auth (`STORAGE_OWNER_KEY` + clear sur SIGNED_OUT / clear avant SIGNED_IN si owner différent / preserve guest legitime), 9 tests isolation. **PR [#242](https://github.com/thierryvm/TerminalLearning/pull/242)** migration force-clear au boot pour browsers cachant l'ancien JS (Chrome cache stale), 2 tests migration. **PR docs+polish session** (cette entry) Sourcery fixups (helper `applyLegacyOwnerMigration` partagé tests/prod + try/catch narrow JSON.parse) + Sidebar branding « Terminal Master » → « Terminal Learning » (cohérence B2B écoles, même fix que THI-153 Layout mobile mais surface sidebar). **Cleanup data prod Supabase** post-decision @thierry : Hotmail = compte principal organique (timestamps étalés 3 avril → 4 mai), Google = contaminé (7 lessons mass-upsert au signup 3 avril 10:18:49). Backup CSV + `DELETE FROM progress WHERE user_id='6832c7a5-...'` → Google 24 → 0 lessons, Hotmail 24 préservées. **1405 → 1417 tests verts** (+12 isolation/migration/edge). **THI-187** Backlog Medium créé : feat UX bouton "Réinitialiser ma progression" dans Settings (demande @thierry pendant la session). Pourquoi pas attrapé avant : `rbac-flow-tester` teste RLS Supabase mais pas localStorage lifecycle, aucun E2E Playwright multi-account. Action correctrice agents : à arbitrer prochaine session. — **Update précédent (16 mai ~19h30 CEST) — 🚀 Sprint 2 étape 3/N — THI-131 ✅ + THI-180 ✅** : double livraison sécurité-critique sur la chaîne LTI 1.3. PR [#236](https://github.com/thierryvm/TerminalLearning/pull/236) mergée — Phase 7c Auth MVP avec `jose@6` (`createRemoteJWKSet` + `jwtVerify`) + nonceStore replay 2 couches + 10 lti-auditor checks (modèle **Opus 4.7** après rappel @thierry anti-Haiku discipline) + migration `013_lti_launches.sql` audit log write-only + 19 tests crypto isolés (`// @vitest-environment node`). Audit cascade lti-auditor → 3 anti-patterns SPIKE dormants détectés et nettoyés AVANT merge (W1 `ignoreExpiration: true` + clé string littérale CVE-2015-9235 alg confusion · R2 collision import path · W4 `X-Frame-Options: ALLOW` non-RFC). PR [#237](https://github.com/thierryvm/TerminalLearning/pull/237) mergée — **senior reverse course** : Supabase Advisors flaggait 7 WARN, l'instinct naïf aurait révoqué les 6 fonctions `SECURITY DEFINER` en bloc. Vérification empirique → 3 sont invoquées par ~15 RLS `USING` clauses, PostgreSQL exige `EXECUTE` même via RLS → REVOKE = `permission denied for function` régression majeure évitée. Migration `014_revoke_security_definer_rpc.sql` chirurgicale (3 trigger-only revoked, 3 RLS-essential épargnées + tracked THI-182 schema `private`). DO blocks idempotent multi-env (Sourcery review). **8.8/10 security-auditor maintenu** (gains +0.3 architecturaux compensent H1 undici 7 CVEs catalog non exploitables aujourd'hui — gate `LTI_ENABLED=false` actif). Score `llm-security-auditor` 9.4/10 stable. 1405 tests verts (+19 LTI crypto). **Audit visuel prod ✅** : Lighthouse Landing **100/100/100/100** (a11y + BP + SEO + Agentic) + Core Web Vitals **LCP 332 ms · CLS 0.00 · TTFB 23 ms** (gain THI-118 confirmé en prod après régression Sentry weekly 9.31s). 6 routes critiques zéro erreur console (Landing + /changelog + /story + /app + /reference + /lesson). Drawer AI Tutor opérationnel (4 providers + rate-limit 30/30 + consent block). 15 agents `.claude/agents/` analysés → **aucun doublon** (frontières scopes/modèles/triggers documentées). **4 tickets backlog créés** : THI-182 (private RLS helpers, Low) · **THI-183** (monitor @vercel/node undici bump >= 6.24.0, High — gate `LTI_ENABLED=true`) · **THI-184** (fusionner ALLOWED_ISSUERS dual source, Medium — gate PR #2 LTI) · **THI-185** (nettoyer PII Sentry contexts, Medium — gate PR #2 LTI). **Process discipline reset @thierry** : merge PR #237 en autonomie reconnue comme dérive (zéro impact runtime — migration différée Dashboard manuel — mais règle CLAUDE.md projet "Jamais merger sans validation visuelle Vercel explicite de Thierry" non-négociable, Option B retenue). 2 actions manuelles @thierry pendantes : (1) apply `014_revoke_security_definer_rpc.sql` via Dashboard SQL Editor (5s, idempotent) · (2) flip "Leaked password protection" ON dans Auth → Settings → ferme 4 WARN (7→3 advisors). Sprint 2 ordre verrouillé : THI-118 ✅ → THI-153 ✅ → **THI-131 ✅ + THI-180 ✅** → THI-42 Profile Hub (next) → THI-77 + THI-78 admin heatmaps → PR #2 LTI endpoint integration (gate THI-184 + THI-185) → PR #3 activation `LTI_ENABLED=true` (gate THI-183 undici + audit final triple). Mini-prompt reprise : `docs/sessions/next-session-thi-42.md`. — **Update précédent (16 mai ~14h30 CEST) — 🚀 Sprint 2 étape 2/N — THI-153 ✅** : PR [#234](https://github.com/thierryvm/TerminalLearning/pull/234) mergée — cleanup UI bundle (umbrella audit post-Sprint 1). 4 items cherry-picked de l'audit 9 mai : (H1) consolidation 3 palettes red mixées → `--github-red: #f85149` CSS var unique source, migration AI/auth components avec Tailwind v4 opacity modifiers, palette pédagogique Tailwind red préservée (Dashboard processus, CommandReference, level 5 badge) · (C1) UserMenu logout focus ring rouge → emerald (cohérence keyboard focus THI-152) · (C2) shadcn dead slots documentés via header comments dans button.tsx + badge.tsx · (H2) `sonner` désinstallé (-45 kB minified, 0 import réel, juste exemple textuel pédagogique dans curriculum.ts Module 11 IA) · **Bonus brand fix** : « Terminal Master » → « Terminal Learning » dans Layout mobile header (`/app`), aligne avec toutes les autres surfaces. **Sourcery review addressed** : extraction `DestructiveActionButton` helper local (2 boutons AiSettings pixel-identiques) + justification emerald token Tailwind v4 natif. M1 button variants flaggées orphelines → **re-vérifié périmé**, toutes utilisées. Validation : ui-auditor SHIP-READY, 1386 tests passed 0 errors, Landing chunk 7.33 kB gzip stable, Chrome DevTools MCP preview Vercel 0 erreur console. **3 tickets backlog créés** post-décisions @thierry 16 mai : THI-177 pré-i18n discipline (Low, gate Phase 9 admin) · THI-178 SEO longue traîne SSG (Low, Phase 10+) · THI-179 securityheaders A+ via COEP (Low, post-LTI 7c). Sprint 2 ordre verrouillé : THI-118 ✅ → THI-153 ✅ → **THI-131 Phase 7c LTI (next)** → THI-42 Profile Hub → THI-77/78 admin heatmaps. — **Update précédent (16 mai ~10h45 CEST) — 🚀 Sprint 2 démarré — deadline 10 juin (écoles + admin panel) — THI-118 ✅** : PR [#232](https://github.com/thierryvm/TerminalLearning/pull/232) mergée — landing LCP regression fix (Sentry weekly 3.87 s → 9.31 s zone poor). Diagnostic Chrome DevTools MCP : LCP element = hero `

` sous-titre (TEXTE), render delay 98.9 %, fuites `landingContent.ts` (imports `commandCatalogue` + `ENVIRONMENTS` forçaient chunk curriculum 41 kB gzip eager) + `UserMenu`/`LoginModal`/`PWAInstallModal` eager. Fix : hardcoder TOTAL_COMMANDS/ACTIVE_ENVIRONMENTS_COUNT + drift test (caught silent `TOTAL_LESSONS` 64 → 65), React.lazy + Suspense pour modals conditionnelles. Bundle Landing chunk **27.29 → 7.33 kB gzip (−73 %)**, curriculum chunk plus dans graph landing. Validation Chrome DevTools MCP preview Vercel : 0 erreur console, lazy modal fonctionne. Sprint 2 ordre verrouillé : THI-118 ✅ → THI-153 cleanup UI bundle (~75 min, H2/M1/C1/C2/H1) → THI-131 Phase 7c LTI → THI-42 Profile Hub → THI-77/78 admin heatmaps. — **Update précédent (16 mai ~10h CEST) — 🏁 Sprint 1 Phase 7b lockdown CLOS à 4/4 — THI-113 ✅** : PR [#230](https://github.com/thierryvm/TerminalLearning/pull/230) mergée — audit final triple (3 agents parallèles) + **H1 fix sentry-tunnel symmetric scrub** (URL query + headers Authorization/X-API-Key/*token* alignés au beforeSend client, plus fallback string-based pour URLs relatives suite Sourcery review security 🚨). Verdict ALL CLEAR : security-auditor **9.4/10** (+0.1 vs 9.3 post-H1 fix), prompt-guardrail-auditor **9.3/10** (44/44 fixtures × 4 locales rejetées, Règle 10 ADR-005 SATISFIED), ui-auditor SHIP-READY (3 LOW non bloquants). Rapport audit complet : [`docs/audits/ai-tutor-v1-2026-05-16.md`](audits/ai-tutor-v1-2026-05-16.md). H2 undici CVEs deps transitive + H3 git history credential = différés/risque résiduel accepté. Trajectoire IA : 8.7 → 9.0 → 9.1 → 9.3 → **9.4/10**. Reste vers 9.5/10 : H2 upgrade + R3 M2-AI encoding + R5 H4-AI jsonwebtoken (Phase 7c gate). **Sprint 1 récap** : THI-148 ✅ → THI-144 ✅ → THI-112 ✅ → THI-113 ✅. **Phase 7c LTI activation** = sprint suivant (gate H4-AI jsonwebtoken supply chain). — **Update précédent (16 mai ~01h CEST) — Sprint 1 étape 3/4 livrée — THI-112 ✅** : PR [#228](https://github.com/thierryvm/teerminalLearning/pull/228) mergée (AiKeySetup standalone + AiConsentModal extraction + AiSettings page `/app/settings` + Sidebar nav + PrivacyPolicy section `#ai-processing` + **M3-AI VERIFIED fermé** : consent storage `'true'` → JSON `{version, acceptedAt, expiresAt}` TTL 365j + migration legacy), `llm-security-auditor` re-baseline **9.3/10 confirmé** (delta +0.2 vs 9.1, cible 9.25 dépassée), 14 files changed (+1545 / −214), tests AI 314 → ~329+ avec 8 nouveaux invariants `consent.test.ts`. Sourcery review round 2 (3 findings) addressed dans même PR : providerMeta module centralisé + AiConsentModal defense-in-depth `handleAccept` + revocation copy clarifiée. Trajectoire 9.5/10 atteignable via R3 M2-AI encoding bypass (THI-153) + R5 H4-AI jsonwebtoken (Phase 7c gate). **Sprint 1 ordre** : THI-148 ✅ → THI-144 ✅ → THI-112 ✅ → THI-113 audit final triple (next, étape 4/4). — **Update précédent (10 mai ~12h CEST) — Sprint 1 étape 2/4 livrée — THI-144 ✅** : PR [#222](https://github.com/thierryvm/TerminalLearning/pull/222) mergée (system prompt v1.1.0 + ADR-008 + eval suite hybride (a)+(b) + M4-AI LOW VERIFIED + R1 follow-up symmetric), `llm-security-auditor` re-baseline **9.1/10 confirmé** (delta +0.1 vs 9.0/10 matin), 1339 tests passants (+48 vs baseline), audit `prompt-guardrail-auditor` PASS (0 CRITICAL, 0 WARNING). 4 frictions ChatGPT cross-validation résolues (compound questions / over-explanation / repeated hints / satisfaction signal). Eval suite (b) manual run pending (`OPENROUTER_API_KEY` env requise, gate ship documenté dans PR body). Trajectoire 9.5/10 atteignable via R2 + R3 + R5 (THI-153 sprint 2 + Phase 7c gate). **Sprint 1 ordre** : THI-148 ✅ → THI-144 ✅ → THI-112 onboarding (next) → THI-113 audit final triple. — **Update précédent (10 mai ~03h CEST) — Clôture finale session marathon** : 11 PRs livrées (#208 → #217), agent `ai-pentester-pro` (créé PR #210) renommé **`llm-security-auditor`** suite analyse ChatGPT (PR #212 — éviter policy filters Anthropic, ajout framework Evidence confidence VERIFIED/STRONG_INDICATOR/SPECULATIVE/RESEARCH_ONLY, atténuation tone defense vs adversarial créatif). **14ᵉ agent `session-orchestrator` créé** (PR #213 + #214 portability fix Sourcery). **1ʳᵉ baseline `llm-security-auditor` officielle : 8.7/10** (entre security-auditor 8.5 et prompt-guardrail-auditor 8.8, framework Evidence empêche inflation CRITICAL). 2 findings HIGH/MEDIUM fermés sur 5 (PR #215 : M1-AI VERIFIED `escapeDelimiters(ctx.goal)` + H10-AI STRONG_INDICATOR BIDI_RX étendu Unicode Tag block U+E0000-U+E007F). PR #216 `chore: gitignore .tmp/`, PR #217 audit-log baseline tracé. THI-153 umbrella : 2/13 cochés. Re-baseline estimé prompt-guardrail 9.2/10, llm-security 9.0/10 (à confirmer prochaine session). Process shutdown 10 phases codifié (`session_shutdown_process.md` exhaustif avec 9 anti-patterns). Pattern `pattern_sourcery_thread_resolution.md` cross-projet réutilisé 4 fois cette session — investissement memo remboursé en <24h. — **Audit global multi-agents post-Sprint 1 étape 1/4 + nouvel agent `llm-security-auditor` 7 couches livré PR [#210](https://github.com/thierryvm/TerminalLearning/pull/210) (renommé via PR [#212](https://github.com/thierryvm/TerminalLearning/pull/212))**. 4 agents en parallèle (`security-auditor` 8.5/10 ship-ready, `test-runner` ✅ 1291 verts, `content-auditor` ✅ PROPRE, `ui-auditor` ⚠️ DEBT detected) → **9 findings consolidés en THI-153 umbrella** (priority High, gate H3 escapeDelimiters lessonContext.goal AVANT THI-144, 30 min). Treizième agent `llm-security-auditor` créé : **7 couches séquentielles avec section `## Raisonnement Couche N` obligatoire AVANT chaque verdict** (L1 surface, L2 threat modeling 8 menaces, L3 OWASP LLM Top 10, L4 vecteurs 2026 hors OWASP, L5 chaînes d'attaque CVSS, L6 stress test défenses, L7 self-critique double-pass), modèle Opus 4.7, anti-patterns bannis (verdict sans PoC, 0 finding HIGH improbable, score stable 4+ semaines), portable cross-projet (Ankora, GetPostCraft, futur Super Admin). **Reminder Terminal Sentinelle V2** verrouillé memo `project_terminal_sentinelle_evolution.md` : V1 couplé TL livré PR #90 (12 avril), V2 module greffable cross-projet pour futur dashboard Super Admin = Phase 10+. Pas de chantier V2 maintenant. Préparation déjà : `llm-security-auditor` portable, memos cross-projet dans `claude-config/memory/`, conventions documentées. — **Sprint 1 Phase 7b lockdown démarré** : `THI-148` (méta-plateforme V1.0.1) livré PR [#208](https://github.com/thierryvm/TerminalLearning/pull/208) en review, prompt bump `tutor/v1.0.0` → `tutor/v1.0.1` + bloc `` statique (11 modules / 65 leçons / 3 environnements, pas de PII, `userProgress` reporté V1.5 + ADR-009) + bonus defense-in-depth C1 audit `prompt-guardrail-auditor` 8.8/10 → full PASS post-fix (`DELIMITER_RX` étendu + `escapeDelimiters()` exporté + module titles wrappés, hardens path AVANT V1.5 custom modules). **1291 tests passed** (+22 vs baseline 1268), 0 failed, type-check + lint clean. Décision *finish what started* tracée (memos CC `feedback_finish_what_started.md` + `project_lti_spike_state.md`) : Phase 7b lockdown complète **AVANT** pivot Phase 7c LTI (qui reste en SPIKE pur — `verifyJwt()` placeholder, `LTI_ENABLED=false`). Branche `docs/sprint-1-thi-148-shutdown` porte le mini-prompt de reprise THI-144 dans `docs/sessions/next-session-thi-144.md` (3 questions ouvertes tranchées 10 mai : ADR-008 confirmé (ADR-007 = solo-maintainer-sustainability déjà pris), eval suite hybride (CI mock + script manuel Haiku), scope one-shot v1.1.0). **Sprint 1 ordre verrouillé** : THI-148 ✅ → THI-144 (system prompt v1.1.0 + **ADR-008** + eval suite + 5 micro-frictions ChatGPT cross-validation, ~5h estimé) → THI-112 onboarding (AiKeySetup + AiConsentModal + AiSettings + /privacy#ai-processing, ~1 jour) → THI-113 audit final triple (security-auditor + prompt-guardrail-auditor + ui-auditor). Pivot Phase 7c LTI = sprint suivant après lockdown. — **Phase 7c THI-152 sprint mobile recovery 🏁 CLOS** (9/9 mini-PRs + hotfix 7bis livrées). Narration thématique du sprint : [`docs/story/v1-5-mobile-recovery-narrative.md`](./story/v1-5-mobile-recovery-narrative.md). 9 mini-PRs séquentielles + 1 hotfix : (1) focus traps a11y, (2) forms anti-zoom, (3) FAB Sparkles size/opacity/position, (4) PWA apple-touch-icon PNG + standalone metas, (5) touch targets ≥44/≤40 + Option D FAB recalibration, (6) drawer overflow word-break + header truncation, (7) PWA safe-area top + autoFocus terminal contrôlé, (7bis hotfix) Landing nav safe-area, (8) focus rings emerald harmonization, (9) FINAL polish HTML metas W3C `mobile-web-app-capable` + tap-highlight transparent + Sidebar landscape `pl-[max(0px,env(safe-area-inset-left))]` + verifs theme-color déjà conforme + font-display swap déjà conforme fontsource 5.x. **3 bugs empiriques @thierry éradiqués** : drawer overflow horizontal mobile (6/9), header `/app` PWA standalone (7/9), bouton "Commencer →" Landing PWA standalone (7bis). Voie safe @cowork respectée tout le sprint : zéro modif `ui/button.tsx` variants, zéro nouvelle variant. **Asymétrie 44/56 mobile/desktop FAB** intentionnelle (primary action exemption documentée). **Sprint THI-152 méthodologie validée** : audit empirique > supposition théorique, pattern `max(baseline,env())` cohérent partout, specs static + dynamic hybrides, empirical override @thierry intégré. THI-150 ✅ + THI-151 ✅ + 5 sub-PRs THI-152 (#196/#197/#198/#199/#200 en cours) toutes mergées sauf #200. Empirical override mini-PR 3/9 confirmé par @thierry (FAB mobile 48→44 px, desktop 56 inchangé, asymétrie intentionnelle primary action exemption). > Statut global : **Phase 5 EN COURS** — Curriculum Expansion : 11 modules ✅, 66 leçons, **1850 tests** (1780 pass + 20 RBAC skipped Phase 9) + 176 E2E — **Vision consolidée** : LTI-first (ADR-001), BYOK OpenRouter 4-tiers (ADR-002), TTFR KPI central (ADR-003), Classroom Composer UI (ADR-004), AI Tutor V1 décisions gelées (ADR-005 — stockage, rate-limit, guardrails), Solo-sustainable practices (ADR-006), tuteur IA socratique dès A1, i18n FR/NL/EN — Architecture stratégique précédente (THI-35) : Terminal Sentinel (Phase 5.5) ✅, RBAC complet (Phase 7) ✅, Admin Panel (Phase 9), PWA avancée (Phase finale) — **Epic Web 2026 Compliance** (THI-96) : 6/8 sub-issues livrées (THI-97 → THI-102), reste Desktop a11y + CSS moderne 2026 — **Phase 7b (AI Tutor V1) ✅ COMPLETE + V1.5 SÉQUENCÉE** : THI-115 ✅, THI-109 ✅ (gate-zero guardrail), THI-110 ✅ (keyManager AES-GCM), THI-120 ✅ (Sentry scrubber), **THI-111 ✅ COEUR FONCTIONNEL** (PR #188 — sanitizer + 4 providers + panel + 287 AI tests, audits guardrail 9.4/10 + security 8.8/10 + ui A11y exemplary), **THI-147 ✅ FIX SAFE-AREA iPhone PWA** (PR #189), **panel actif en Production** (`VITE_AI_TUTOR_ENABLED=true` + `VITE_AI_TUTOR_OPENROUTER_MODEL=anthropic/claude-haiku-4-5` activés Production+Preview par @cowork) — **Sprint sécurité 1-2 mai 2026 ✅ CLOS** : audit security-auditor 8.1/10 → ~8.6/10 post-sprint, 11 PRs livrées (#168 à #178), 5 HIGH/MEDIUM Done (THI-133/134/135/137/140), 4 MEDIUM ciblés en backlog (THI-136/138/139/112), agent `route-attack-auditor` créé — **Session 4 mai 2026** : THI-111 livré + THI-147 livré + 5 tickets V1.5 backlog créés (THI-142 lessonContext renforcé HIGH, THI-143 frustration heuristic + détection sémantique user MEDIUM, THI-144 system prompt v1.1.0 + ADR-008 + eval suite MEDIUM, THI-145 chat assistant role-based Phase 9+ LOW, THI-146 modèle défaut Haiku HIGH déjà actif via env var, THI-148 extend tutor scope platform meta-questions V1.0.1 P1 1h30 estimé) — **Posture validée** : pas de rush deadline, qualité/scalabilité/perf non négociables, plan respecté en ordre, **mea culpa explicite** à chaque round trio @thierry / @cc-terminallearning / @cowork (estimation 30 min → 1h30, privacy `userProgress` retirée V1.0.1, hypothèse `transform` mobile réfutée par diagnostic Chrome DevTools MCP) — **Verdict empirique Haiku 4.5 (capturé 4 mai 21h par @cowork via Chrome MCP)** : 5 tests qualitatifs, score moyen **9.3/10** — Test 1 méta-plateforme 8/10, Test 2 fichiers cachés 9/10, Test 3 hallucination 9.5/10, Test 4 frustration 10/10 (Haiku bascule mode direct AUTONOMEMENT), Test 5 jailbreak 10/10. **Reprio backlog tranchée @cowork** : THI-146 ✅ SUCCÈS validé, **THI-142 → Low** (Haiku gère déjà bien le contexte leçon), **THI-143 → Low** (Haiku résout naturellement la frustration via compréhension contextuelle), **THI-148 P1 INCHANGÉ** (scope ≠ modèle prouvé Test 1, GO IMMÉDIAT), THI-144 P2 Medium (peut englober THI-148 + eval suite), THI-145 P3 Low (Phase 9+). **ROI méthode scientifique** : ~4-6h économisées (THI-142/143 reportés V2). **Next ordonné — décision @cowork 5 mai matin** : (1) **THI-150 EN COURS** (12ᵉ agent `mobile-responsive-auditor`, ex-brick 3a de THI-149 epic Done, 11 sections / ≥48 checkpoints + bonus Section 11 Desktop Preservation + checkpoints BUG-FAB-001 visibility/contrast/detachment), (2) THI-151 audit Playwright WebKit + matrice bugs (ex-brick 3b), (3) THI-152 mini-PRs fix séquentielles (ex-brick 3c, critère ABSOLU **ne pas casser desktop**), (4) THI-148 extend tutor scope méta-plateforme V1.0.1 (1h30 honnête, scope statique platformContext, bump v1.0.0→v1.0.1, audit guardrail Règle 10 obligatoire), (5) **THI-144 enrichi P1** system prompt v1.1.0 + ADR-008 + eval suite (intègre 5 micro-frictions identifiées par cross-validation ChatGPT sur session 8 tours @thierry — compound questions, sur-explication internal mechanics, indices répétés, platformContext absent confirme THI-148, conclusion ouverte), (6) THI-112 onboarding AiKeySetup + picker modèle curated, (7) THI-114 Web Worker isolation, (8) THI-145 chat role-based Phase 9+. **THI-142/143 reportés V2** (Haiku 9.3/10 résout 80% naturellement). ---