Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .claude/review-guidelines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Guidelines de revue — TalkControl

Dettes **éliminées par le plan d'amélioration 2026-07** (`docs/improvements/`). Une revue de code
sur ce repo doit empĂŞcher leur retour. Utilisables manuellement avec `/code-review` (pas de revue
CI automatisée : la politique Actions de l'org n'autorise que les actions github-owned — voir IMP-011).

## Bloquant (dette qui revient)

- **Casts `as` sur les payloads du bus** : consommer via `TcEventMap`/`PayloadFor<K>`
(`src/common/event-bus/events.ts`), jamais `data as {...}` (IMP-007). Les seuls casts tolérés
sont les casts-frontière documentés inline (socket.io, pass-through plugins, `currentSlide as
Slide` du moteur) — un nouveau cast non documenté est un défaut.
- **`any` / `as any`** : interdits (le `this as any` historique a été résolu par une interface —
faire pareil).
- **`console.*` bruts** : passer par `src/common/services/logger.ts`. Exception assumée :
`get-started.ts` (bannière CLI).
- **Secrets** : aucun token dans un fichier versionné ; `config/config.json` reste gitignored ;
token ngrok = `NGROK_AUTHTOKEN` (IMP-003). Aucune URL ngrok personnelle.
- **CORS `*`** : les 3 surfaces (Express, socket.io, Vite dev server) passent par l'allowlist
`buildCorsOptions` (`src/common/services/cors.ts`) — tout retour d'un `*` est une régression (IMP-003).
- **`innerHTML` non contrôlé** : seul usage légitime = `unsafeHTML` explicite sur contenu déjà
filtré par l'anti-SSRF (notes). Pas de nouvelle injection de HTML brut.
- **Événement bus non typé** : tout nouvel événement s'ajoute à `TcEventMap` ; pas de
`on('nouvelEvent', …)` hors map. Pas de surcharges sur `on`/`broadcast` (le fallback `string`
avale silencieusement les erreurs de payload — IMP-007).
- **Anti-SSRF contourné** : toute cible patcher/proxy passe par
`src/server/services/presentation-url.ts` (IMP-001). Pas de fetch/proxy d'URL non validée.
- **Broadcast hors room** : toute émission serveur reste dans `session:<id>` (`io.to`), jamais
globale (IMP-002).
- **Seuils de coverage baissés** ou tests supprimés pour faire passer la CI.

## Bloquant (contraintes de stack)

- **Décorateurs Lit standards** : legacy uniquement (`experimentalDecorators: true`) — les
standards cassent au runtime avec oxc/Rolldown + Chromium (IMP-006).
- **Réintroduction** de webpack, babel, mocha, redux, `--legacy-peer-deps` : migration terminée.
- **e2e `workers > 1`** : interdit tant que le store serveur est global (IMP-002).
- **Action GitHub tierce** dans un workflow : la politique org n'autorise que `actions/*`.

## À challenger (pas bloquant, mais motiver)

- Renommage de variables/clés existantes sans nécessité fonctionnelle.
- Nouvelle dépendance (KISS : le plan en a retiré plus qu'ajouté).
- Nouvelle abstraction à un seul site d'usage (cf. IMP-009 : la dédup à un appelant unique a été
refusée).
37 changes: 37 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"permissions": {
"allow": [
"Bash(npx tsc *)",
"Bash(npm run *)",
"Bash(npm test)",
"Bash(npm test *)",
"Bash(NODE_ENV=test npm test)",
"Bash(NODE_ENV=test npm test *)",
"Bash(NODE_ENV=test npm run *)",
"Bash(./scripts/verify.sh)",
"Bash(npm audit)",
"Bash(npm audit *)",
"Bash(npm ci)",
"Bash(npm install *)",
"Bash(npm ls *)",
"Bash(npm view *)",
"Bash(npm info *)",
"Bash(npm outdated *)",
"Bash(npx vitest *)",
"Bash(npx playwright *)",
"Bash(npx tsx *)",
"Bash(git status *)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git show *)",
"Bash(git branch *)",
"Bash(git checkout *)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(git fetch *)",
"Bash(git pull *)",
"Bash(git stash *)",
"mcp__playwright"
]
}
}
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,9 @@ test/**/__screenshots__/
# Local config: may carry the ngrok token and is rewritten at runtime with
# tunnel urls — recreated from config/config.example.json by npm install
config/config.json

# Claude Code : seuls settings.json et review-guidelines.md sont versionnés,
# le reste de .claude/ est de l'état local de session
.claude/*
!.claude/settings.json
!.claude/review-guidelines.md
19 changes: 19 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# TalkControl — instructions agents (tous outils)

Ce fichier s'applique Ă  tout agent de code (Gemini/Antigravity, Claude Code, autres).
**Le contexte projet complet est dans [CLAUDE.md](CLAUDE.md) — lis-le en premier**, il vaut
pour tous les outils (le nom est historique, pas une exclusivité).

L'essentiel, si tu ne lis qu'ici :

- Télécommande de présentations reveal.js : 3 services (tc-server :3001, controller :3000,
showcase :3002), event-bus typé `TcEventMap`, store maison (pas Redux), Lit en décorateurs
**legacy** (ne pas passer aux décorateurs standards — cassent au runtime).
- **Validation complète avant commit** : `./scripts/verify.sh` (tsc, lint:check, coverage avec
seuils, e2e, build, audit, docs). Rapide pendant le dev : `npx tsc --noEmit`,
`npm run lint:check`, `NODE_ENV=test npm test`, `npm run test:components`.
- Contrat iso-fonctionnel : `docs/migration/golden-path.md`, couvert par `e2e/golden-path/`.
- Commits Gitmoji en français, branches `feat|fix|chore|test/<slug>`, KISS/SOLID/TDD.
- Ne pas renommer l'existant sans raison fonctionnelle ; ne jamais committer
`config/config.json` ni un secret ; ne jamais baisser un seuil de coverage.
- Guidelines de revue : `.claude/review-guidelines.md`.
91 changes: 91 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# TalkControl — contexte agent

Télécommande de présentations reveal.js. Une instance = **un présentateur à la fois** (IMP-002).

## Architecture (3 services)

| Service | Port | RĂ´le |
| ---------------------- | ---- | -------------------------------------------------------------------------------- |
| tc-server | 3001 | Express 5 + socket.io, patcher/proxy des présentations, moteur d'état des slides |
| controller + component | 3000 | Vite dev server, layouts (presenter, on-stage…) et web components Lit |
| showcase | 3002 | Présentation reveal.js d'exemple (http-server) |

Flux : controller ↔ serveur ↔ component via **event-bus typé** (`src/common/event-bus/`,
`TcEventMap`, 21 événements — IMP-007). Pairing par session socket.io : token UUID opaque `?s=`,
« le secret est l'id », rooms `session:<id>` (IMP-002). Store serveur **maison** (~35 lignes,
`src/server/store/`), union discriminée `TcAction` — Redux a été retiré (IMP-008). Plugins
auto-découverts par `import.meta.glob('./input/*/index.ts')`, activation pilotée par
`config/plugins.json` (IMP-010).

## Stack

Node 24 (`.nvmrc`), TypeScript strict, Vite 8 (Rolldown/oxc), Vitest 4 (jsdom + browser mode
Chromium), Playwright e2e, Lit 3, Express 5, socket.io 4, Bulma 1, VitePress 2-alpha + TypeDoc.
**Plus de** webpack, babel, mocha, redux : migration v0.5.0 terminée, n'en réintroduis aucun.

## Validation

Pendant le dev (rapide) :

```bash
npx tsc --noEmit # 0 erreur
npm run lint:check # 0 erreur (lint = --fix, ne pas l'utiliser pour valider)
NODE_ENV=test npm test # suite jsdom
npm run test:components # suite browser (Chromium réel)
```

Avant commit / PR — **validation complète, miroir de la CI** (`.github/workflows/develop.yml`) :

```bash
./scripts/verify.sh
```

soit : `tsc --noEmit`, `lint:check`, `NODE_ENV=test npm run coverage` (jsdom + browser + merge —
les suites tournent DANS coverage, ne pas les relancer Ă  part : IMP-013), `test:e2e` (Playwright
démarre lui-même les 3 services), `build`, `npm audit` (0 vulnérabilité attendu), `docs:build`.

## Contrat iso-fonctionnel

`docs/migration/golden-path.md` fait foi : le comportement utilisateur décrit là est le contrat,
couvert par les e2e (`e2e/golden-path/`). Refactors internes libres tant que les suites passent.

## Conventions

- Commits **Gitmoji, messages en français** (voir l'historique récent) ; branches `feat|fix|chore|test/<slug>`.
- KISS d'abord, SOLID, TDD quand la tâche s'y prête.
- **Ne pas renommer** les variables/clés existantes sans nécessité fonctionnelle
(ex. `config.logger.redux` est un nom de clé de config conservé exprès).
- Secrets : `config/config.json` est **gitignored** (recréé par le postinstall depuis
`config.example.json`) — ne jamais le committer, ne jamais y référencer un vrai token.
Token ngrok via `NGROK_AUTHTOKEN`. Aucune URL ngrok personnelle dans les fichiers versionnés.
- Ne jamais baisser un seuil de coverage (80/90/70/80 lignes/fonctions/branches/statements,
appliqués au merge) pour faire passer la CI.
- Revue : guidelines projet dans `.claude/review-guidelines.md` (dettes éliminées par le plan
d'amélioration — à ne pas laisser revenir). Utilisable avec `/code-review`.

## Pièges connus (vécus, pas théoriques)

- **Décorateurs Lit LEGACY** (`experimentalDecorators: true`), PAS standards : oxc/Rolldown ne
lowere pas les décorateurs TC39 et Chromium ne les exécute pas nativement → `SyntaxError` runtime.
`useDefineForClassFields: false` requis. Ne pas « moderniser » vers les décorateurs standards (IMP-006).
- `NODE_ENV=test` obligatoire pour `npm test` et `npm run coverage`.
- `vitest run | tail` masque le code de sortie (exit = celui de `tail`) → utiliser `PIPESTATUS`.
- e2e : `workers: 1` obligatoire (store serveur global partagé — IMP-002) ; flake connu :
`15-remote-control` « onglet restauré » peut échouer au 1er run puis repasser.
- e2e en local : `reuseExistingServer` ne sonde QUE le port 3000 — un Vite résiduel là suffit
pour que Playwright ne démarre NI tc-server (:3001) NI showcase (:3002) → ~11 échecs en masse.
Avant d'incriminer le code : `lsof -iTCP:3000,3001,3002 -sTCP:LISTEN` et tuer les résidus.
- Cache Vite pollué → e2e qui cassent en masse (`Unexpected token 'export'`) :
`rm -rf node_modules/.vite` avant de chercher plus loin.
- Alias de paths : source unique `vite.aliases.ts` (miroir de `tsconfig.json` `paths`), partagée
par les 3 configs Vite/Vitest — modifier les deux ensemble.
- `import.meta.glob` est Vite-only : le plugin-loader est client-only, ne pas l'importer côté serveur.
- Politique GitHub Actions de l'org TalkControl : **actions `actions/*` github-owned uniquement**,
aucune action tierce Marketplace ne s'exécutera (élargissement = admin org).
- Doc API : TypeDoc (via `scripts/jsdoc-build.mjs`), pas jsdoc — jsdoc ne parse pas le TypeScript (IMP-014).

## Protocole d'exécution d'une étape du plan

Voir `docs/improvements/README.md` (branche → lecture du step → TDD → validation → commits
Gitmoji → documentation → rollback). Décisions structurantes tracées dans
`docs/improvements/decisions.md` (`IMP-XXX`).
18 changes: 10 additions & 8 deletions docs/improvements/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ Chaque étape suit ce cycle. Les fichiers `step-XX` ne le répètent pas — il
1. **Branche** : `git checkout develop && git pull && git checkout -b <type>/step-XX-<slug>` (type = `feat|fix|chore|test` selon l'étape).
2. **Lire le fichier d'étape en entier** avant de toucher au code. Vérifier que l'état actuel décrit correspond toujours au code (le plan peut avoir vieilli — si divergence, le signaler et adapter, ne pas appliquer aveuglément).
3. **TDD quand l'étape s'y prête** : écrire/adapter les tests d'abord, les voir échouer, implémenter.
4. **Validation systématique** avant commit (en plus des validations spécifiques de l'étape) :
4. **Validation systématique** avant commit (en plus des validations spécifiques de l'étape) —
`./scripts/verify.sh` (étape 17) enchaîne le tout, miroir de la CI :
```bash
npx tsc --noEmit # 0 erreur
npm run lint # 0 erreur
NODE_ENV=test npm test # suite jsdom verte
npm run test:components # suite browser verte
npm run test:e2e # suite e2e verte
npm run build # build Vite OK
npx tsc --noEmit # 0 erreur
npm run lint:check # 0 erreur (lint = --fix, pas une validation)
NODE_ENV=test npm run coverage # suites jsdom + browser + merge, seuils 80/90/70/80 (IMP-013)
npm run test:e2e # suite e2e verte (Playwright démarre les 3 services)
npm run build # build Vite OK
npm audit # 0 vulnérabilité
npm run docs:build # doc VitePress + TypeDoc OK
```
5. **Commits Gitmoji** (convention du repo), messages en français comme l'historique récent, un commit par unité logique.
6. **Documenter** : cocher l'étape dans ce README, compléter le `step-XX.md` avec la section « Résultats de validation » (comme dans `docs/migration/`), ajouter un `IMP-XXX` dans decisions.md si une décision a été prise.
Expand Down Expand Up @@ -99,7 +101,7 @@ Garde-fous quel que soit le modèle : exécuter réellement les 6 commandes de v

| Étape | Statut | Contenu |
|---|---|---|
| [17 — Socle agentic](step-17-agentic.md) | ⬜ | CLAUDE.md, .claude/ versionné, skills de vérification, revue IA automatisée |
| [17 — Socle agentic](step-17-agentic.md) | ✅ | CLAUDE.md + AGENTS.md, `.claude/settings.json` + review-guidelines versionnés, `scripts/verify.sh` (IMP-011) — revue CI écartée (politique Actions org), `/code-review` manuel |

## Dépendances entre étapes

Expand Down
61 changes: 57 additions & 4 deletions docs/improvements/decisions.md
Original file line number Diff line number Diff line change
Expand Up @@ -555,11 +555,64 @@ golden-path 14 (menu plugins) vert, audit 0 vulnérabilité.

## IMP-011 — Socle agentic versionné

**Étape :** 17 | **Statut :** ⬜
**Étape :** 17 | **Statut :** ✅ tranché et implémenté (2026-07-14, branche `chore/step-17-agentic`)

### Décision (à confirmer)
CLAUDE.md + AGENTS.md + `.claude/settings.json` propre + skill/script de vérification + revue CI automatisée
avec guidelines encodant les dettes éliminées. KISS : simple et maintenable à 6 mois.
### Contexte
Aucune configuration agentic versionnée alors que le projet est développé quasi exclusivement avec
des agents : chaque session repartait de zéro. Seul artefact : un `.claude/settings.local.json`
local pollué (139 entrées, PIDs codés en dur, chemins `/tmp`, références Mocha mortes).

### Décision — le socle retenu (4 fichiers versionnés + 1 script)
- **`CLAUDE.md`** (racine) : contexte projet dense — architecture 3 services + event-bus, stack,
commandes de validation canoniques (celles réellement exécutées par la CI de l'étape 16),
contrat golden-path, conventions, et les **pièges réellement vécus** pendant les étapes 01-16
(décorateurs Lit legacy IMP-006, `NODE_ENV=test`, `PIPESTATUS`, `workers: 1`, cache Vite,
`vite.aliases.ts`, politique Actions org, TypeDoc IMP-014).
- **`AGENTS.md`** minimal (interop Gemini/Antigravity et autres outils) : renvoie vers CLAUDE.md
et inline l'essentiel (validation, conventions, interdits) pour les outils qui ne suivraient pas
le lien. Pas de symlink (fragile cross-plateforme) : deux fichiers, CLAUDE.md source de vérité.
- **`.claude/settings.json`** versionné : allowlist générique (validation, git usuel, npm, npx
outillage, MCP playwright). Le `settings.local.json` (non versionné) est régénéré épuré : entrées
rtk/mempalace/gh/pkill machine-spécifiques conservées, tout le mort supprimé. `.gitignore` :
`.claude/*` ignoré sauf `settings.json` et `review-guidelines.md` (exclut scheduled_tasks.lock,
worktrees/, settings.local.json).
- **`scripts/verify.sh`** (option KISS retenue contre une skill `.claude/skills/verify-talkcontrol/`) :
enchaîne tsc, lint:check, `NODE_ENV=test coverage` (les suites tournent dedans — pas de double
exécution, cohérent IMP-013), e2e, build, audit, docs:build, avec récapitulatif et exit code
agrégé. Un script shell est lisible, testable et **utilisable par n'importe quel outil** (pas
seulement Claude Code) — c'est le choix qui reste vrai à 6 mois. Le protocole de
`docs/improvements/README.md` § 4 est harmonisé sur cette liste (il datait d'avant l'étape 16 :
`lint` au lieu de `lint:check`, pas de coverage/audit/docs).
- **`.claude/review-guidelines.md`** : encode les dettes éliminées par le plan (casts `as` de
payload, `any`, `console.*` bruts, secrets, CORS `*`, `innerHTML`, événements bus hors
`TcEventMap`, contournement anti-SSRF, broadcast hors room, baisse de seuils, décorateurs
standards, réintroduction webpack/babel/mocha/redux) pour une revue `/code-review` manuelle.

### Revue de code automatisée en CI : écartée (option 4 du step)
La politique GitHub Actions de l'organisation TalkControl est `selected` avec uniquement
`github_owned_allowed: true` (constat étape 16) : `anthropics/claude-code-action` n'est pas
github-owned et ne s'exécuterait pas. L'autoriser exigerait un élargissement de la politique org
(`admin:org`, action manuelle de JF) **plus** un secret `ANTHROPIC_API_KEY` facturé à chaque PR.
Contre le critère KISS de l'étape (« si simple que ça reste vrai dans 6 mois »), le ratio
bénéfice/maintenance ne tient pas pour un repo à contributeur quasi unique qui revoit déjà chaque
PR. **Évolution documentée** si le besoin devient réel : élargir la politique org à l'action
Claude Code, provisionner le secret, et brancher `.claude/review-guidelines.md` (déjà écrit pour
ça) comme contexte de revue.

### Conséquences
Une session d'agent neuve trouve dans CLAUDE.md le contexte, les commandes exactes et les pièges
sans redécouverte ; la validation complète tient en une invocation (`./scripts/verify.sh`) ; les
permissions partagées sont propres et versionnées. Validation : verify.sh exécuté en réel sur la
branche (voir step-17, « Résultats de validation »).

### Critère pour rouvrir la question des skills (challengé et confirmé au merge)
Faits et pièges → CLAUDE.md ; séquences déterministes → script ; une skill `.claude/skills/`
seulement pour une procédure **fréquente, multi-étapes, à jugement**, trop grosse pour le contexte
permanent — aujourd'hui cette case est vide (le seul workflow répétitif, « exécuter une étape du
plan », s'éteint avec le plan). Candidats identifiés si le développement actif reprend :
`/new-plugin` (scaffold + conventions IMP-010) et `/smoke` (golden-path manuel via Playwright MCP,
pièges de l'étape 05). Déclencheur concret : réexpliquer la même procédure dans un prompt pour la
3e fois — ce prompt est le brouillon de la skill.

---

Expand Down
Loading