feat(persistence): P8b — écriture providers.json (resumable par provider)

Au lancement structuré, le resumable exposé par le moteur est rangé dans
providers.json sous (id de paire, provider) — best-effort, n'altère jamais le
lancement.

- domaine : StructuredAdapter::provider_key() ⇒ "claude"/"codex" (clé stable
  par famille, lisible, indépendante de l'uuid d'instance)
- application : port ProviderSessionProvider (root par appel) +
  with_provider_session_provider ; helper persist_provider_session dans
  launch_structured (skip si provider/adapter/id moteur absents ou set KO)
- app-tauri : AppProviderSessionProvider (FsProviderSessionStore sur le root)
- tests : 6 cas (nominal claude/codex, no-op sans provider/sans id moteur,
  best-effort, mapping provider_key) ; domain+application verts

Lecture du store pour --resume = P8c.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 18:36:19 +02:00
parent 09cc8f0902
commit 9b053216e3
6 changed files with 430 additions and 5 deletions

View File

@ -134,6 +134,24 @@ pub enum StructuredAdapter {
Codex,
}
impl StructuredAdapter {
/// Clé **stable par famille de moteur** (provider), indépendante de l'uuid
/// d'instance d'un profil. Sert de clé dans `providers.json` (lot P8b) : un swap
/// d'un profil vers un autre profil de **la même famille** réutilise la même
/// entrée (resumable partagé), et le fichier reste lisible à l'œil.
///
/// Mapping : `Claude → "claude"`, `Codex → "codex"` (aligné sur la sérialisation
/// camelCase de l'enum, mais figé ici comme **contrat de persistance** : ce
/// mapping ne doit pas dériver si la représentation serde change).
#[must_use]
pub const fn provider_key(self) -> &'static str {
match self {
Self::Claude => "claude",
Self::Codex => "codex",
}
}
}
/// Transport du serveur MCP IdeA exposé à une CLI (détail invisible au domaine).
///
/// `stdio` = défaut robuste cross-OS ; `socket` = optimisation (point ouvert).