Files
IdeA/.ideai/briefs/d7-menu-restreint.md
Blomios 6de4e5a6e0 feat(agent): menu de profils restreint Claude/Codex + retrait custom (D7) — §17
Dernier lot de §17 : seuls les profils pilotables en mode structuré sont
proposés à la sélection/création.

- domain : AgentProfile::is_selectable() = structured_adapter.is_some(),
  source unique de vérité du prédicat.
- infrastructure : AgentSessionFactory::supports délègue à is_selectable
  (supports et is_selectable ne peuvent plus diverger).
- application : selectable_reference_profiles() = reference_profiles()
  filtré ; ReferenceProfiles et FirstRunState exposent la liste filtrée
  (Claude/Codex). reference_profiles() brut reste à 4 (data intacte) ⇒
  un agent Gemini/Aider/custom legacy déjà configuré continue de tourner.
- frontend : bloc AddCustomProfile retiré du wizard first-run, action
  addCustom retirée du viewmodel ; wizard n'affiche que la liste filtrée.

Tests (QA) : is_selectable (table de vérité), cohérence stricte
is_selectable<->supports, liste exposée=2 / data brute=4, garde
anti-régression Vitest sur l'absence du bloc custom — validées par
mutation. cargo test --workspace : 820 passed. npx vitest run : 344 passed.

§17 COMPLET (D0->D7). Suivi restant : D6b (surfacer reply dans le writer
wire .response.json pour la délégation par protocole fichier).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 23:57:51 +02:00

5.7 KiB

Brief Dev — Lot D7 : menu de profils restreint + retrait custom (§17.9)

Demandé par Main à DevBackend + DevFrontend + QA. Cycle §3. Dernier lot de §17. Back + front. DevBackend livre le contrat, DevFrontend consomme.

0. Objectif (§17.3 / §17.6)

Tant que seuls Claude et Codex ont un adapter structuré, le menu de sélection de profil IA ne doit proposer que des profils pilotables en mode structuré. Conséquences :

  • Gemini / Aider (présents dans le catalogue de référence mais sans structured_adapter) ne sont plus proposés à la sélection.
  • Le profil custom est retiré (l'utilisateur ne peut plus saisir une commande arbitraire, car on ne saurait pas la piloter en structuré).

Principe : is_selectable(profile) == structured_adapter.is_some() (équivaut à AgentSessionFactory::supports(profile)). C'est ce prédicat qui filtre la liste exposée (wizard first-run et création/édition d'agent).

Note : on ne casse pas le modèle AgentProfile (un profil sans adapter reste un profil PTY/legacy valide, §17.3). On restreint seulement ce qui est proposé à la sélection.

1. Côté DevBackend (crates/)

  1. Prédicat de sélectionnabilité centralisé : is_selectable(&AgentProfile) -> bool (= structured_adapter.is_some()). Place-le là où c'est cohérent (catalogue/usecases agent). Évite de dupliquer la logique ; si AgentSessionFactory::supports existe déjà (livré D2), garde la même sémantique (les deux doivent rester d'accord).
  2. Exposer uniquement les profils sélectionnables au chemin de sélection : le use case qui alimente le wizard/la création (autour de ReferenceProfiles / reference_profiles() dans crates/application/src/agent/{catalogue,usecases}.rs) doit filtrer sur is_selectable. Gemini/Aider restent dans le catalogue data (ne les supprime pas du modèle) mais n'apparaissent pas dans la liste proposée. Décide proprement : soit un nouveau champ selectable: bool sur le DTO exposé, soit une liste déjà filtrée — choisis l'option la moins ambiguë pour le front et documente-la.
  3. Retrait custom (back) : si une commande/usecase accepte un profil custom arbitraire pour la sélection/création depuis le wizard, neutralise ce chemin (ou documente qu'il n'est plus appelé). Ne casse pas la persistance de profils existants.
  4. Vérifie cargo build -p domain -p application -p app-tauri.

Contrat à livrer à DevFrontend (à mettre dans ton rapport) : la forme exacte de ce que le front reçoit (liste filtrée ? champ selectable/structuredAdapter sur ProfileDto ?) pour qu'il sache quoi afficher et quoi masquer. Rappel : ProfileDto(pub AgentProfile) sérialise déjà structuredAdapter (camelCase) — tu peux t'appuyer dessus plutôt que d'ajouter un champ.

2. Côté DevFrontend (frontend/src/)

Ne démarre qu'après le contrat de DevBackend (Main te relaiera la forme exacte).

  1. Wizard first-run (features/first-run/FirstRunWizard.tsx, ProfilesSettings.tsx) :
    • n'affiche que les profils sélectionnables (Claude/Codex) ;
    • retire le bloc AddCustomProfile (onAdd/vm.addCustom, emptyCustomProfile, aria-label="add custom profile") — le bouton/forme custom disparaît.
  2. Sélecteur d'agent (création/édition dans features/agents/) : même filtre — seuls Claude/Codex proposés ; pas d'option custom.
  3. Nettoie le code mort résultant (helpers emptyCustomProfile, validation custom) uniquement s'il n'est plus référencé ailleurs — sinon laisse-le et signale-le.
  4. Vérifie cd frontend && npm run build.

3. Invariants

  • Zéro régression : la persistance/édition des profils déjà configurés n'est pas cassée ; un projet existant avec un agent Gemini/Aider/custom legacy continue de fonctionner (on restreint la création, pas l'exécution de l'existant).
  • Le prédicat is_selectable est la source unique ; back et front doivent rester cohérents.
  • Frontières : le front filtre/affiche selon le contrat du port, le back décide la sélectionnabilité.

4. Tests attendus (QA)

Rust (-p application/app-tauri) :

  • is_selectable vrai pour Claude/Codex, faux pour Gemini/Aider.
  • la liste exposée à la sélection ne contient que Claude/Codex (custom absent).
  • non-régression : reference_profiles() (catalogue brut) contient toujours les 4 (data intacte).

Vitest (frontend) :

  • le wizard first-run n'affiche que Claude/Codex ; le bloc custom est absent (aria-label="add custom profile" introuvable).
  • le sélecteur de création d'agent ne propose que Claude/Codex, pas de custom.
  • garde anti-always-green : un test qui vérifie l'absence du custom doit échouer si le bloc réapparaît (assertion sur non-présence d'un testid/label précis).

5. Méthode

DevBackend → contrat + build vert → Main relaie à DevFrontend → build vert → QA écrit+exécute (cargo test --workspace ET npx vitest run) → vert. Rapport d'erreurs clair si rouge. Ne pas committer, ne pas push.

6. Références

  • Catalogue : crates/application/src/agent/catalogue.rs (reference_profiles() : claude+codex with_structured_adapter, gemini+aider sans) ; use cases : …/agent/usecases.rs (ReferenceProfiles).
  • Factory : AgentSessionFactory::supports (livré D2, crates/infrastructure/src/session/factory.rs).
  • DTO : crates/app-tauri/src/dto.rs (ProfileDto/ProfileListDto).
  • Front : frontend/src/features/first-run/{FirstRunWizard,ProfilesSettings}.tsx, frontend/src/features/agents/, frontend/src/domain/index.ts (emptyCustomProfile).
  • Spec : ARCHITECTURE.md §17.3, §17.6 et tableau §17.9 ligne D7.