--- issueRef: "#65" version: 6 updatedBy: {"kind":"agent","agent_id":"a6ced819-b893-4213-b003-9e9dc79b9641"} updatedAt: 1784202758668 --- # Ticket #65 — Serveur headless `idea-serve` (carnet de chantier) Statut : **QA — en attente de validation live utilisateur (non-régression desktop)**. Branche : `feature/ticket65-idea-serve-headless` (base `develop` @ `506d589`). Local, aucune action sortante. ## Arbitrages Architect (tranchés) - **DTO/events → propriétaire canonique = crate `backend`.** PAS de crate `presentation-dto`/`backend-api` : `backend` est déjà le composition root transport-neutre et la façade des use cases pour adapters entrants. `web-server` ET `app-tauri` le consomment ⇒ contrat canonique partagé entre deux driving adapters. - **Frontière** : les DTO dans `backend` ne tirent NI Tauri, NI HTTP/WS/cookies, NI Axum/Hyper, NI UI. `domain`/`application` ne dépendent PAS des DTO. Vérifié QA. - **Dédup events = dans L1, pas en dette** (sinon deux sources de vérité au moment où #65 stabilise le contrat). Dette acceptable uniquement pour le Tauri-spécifique (relay `app_handle.emit`, wiring runtime). ## Structure cible (livrée) - `crates/backend/src/dto.rs` + `crates/backend/src/events.rs` ; `lib.rs` expose `pub mod dto; pub mod events;` - `app-tauri/src/dto.rs` = shim `pub use backend::dto::*;` - `app-tauri/src/events.rs` = relay Tauri uniquement, DTO importés de `backend::events`. - `web-server` consomme `backend::{dto, events}`. ## Livré — L1/L2/L3 + run_embedded Commits : `82e8e77` (wip de sûreté, ne fige rien) · `ddbea7b` (dédup DTO events). `web_server::run_embedded(...)` présent : `ServerConfig`, `EmbeddedServerHandle`, `url()`, `pairing_code()`, `state()`, `stop()`, shutdown via `oneshot`. **C'est le point d'extension qui prépare #68** (le desktop consommera `web-server` comme lib, pas de fork). ## Vérif QA (exécution réelle) — VERT - `cargo build -p web-server --bin idea-serve` + `-p app-tauri --bin app-tauri` : OK. - `cargo test -p backend` 41 passed · `-p web-server` 55 passed · `-p app-tauri` 35 passed. - **Invariant clé** : `ldd target/debug/idea-serve | rg -i 'webkit|javascriptcore|gtk|gdk|soup|tauri|wry'` → **aucune sortie**. Comparatif `app-tauri` tire bien libwebkit2gtk/libgtk/libsoup/libjavascriptcore. - Contrat HTTP/WS inchangé (55 tests web-server : pair/invoke/logout/ws/static/allowlist/B8). `git diff --name-only 506d589...HEAD -- frontend` → **vide**. ## Faux mystère élucidé (à ne pas refaire paniquer) `cargo test -p app-tauri` est passé de **45 → 35** : les tests ne sont PAS perdus, ils ont MIGRÉ. Écart réel depuis develop = **68 tests déplacés** (`src/lib.rs` : 104 → 36) : 55 `server::tests::*` → `web-server`, 10 `events::tests::*` → `backend::events`, 3 `dto::ls6_pagination_tests::*` → `backend::dto`. Vérifié par `cargo test -p app-tauri -- --list` comparé sur `506d589`. ## Faux négatif connu (arbitré NON bloquant) `cargo test --workspace` : 10 échecs `infrastructure::session::openai_compat::*` + `factory_routes_openai_compatible_to_http_session` sur `bind: Os { code: 1, kind: PermissionDenied }` = la sandbox interdit l'écoute réseau. **Confirmé préexistant sur `506d589`** (même liste). Validation retenue par crates ciblés. ## Réserve QA restante Aucun test dédié à `run_embedded().stop()` (un test de bind réel serait soumis à la même restriction sandbox). À couvrir dans #68, qui consommera ce handle. ## Incident de topologie (résolu — leçon) DevBackend a d'abord travaillé sur la branche de #69 sans committer. Git a rapatrié le diff Rust (stash `-u` limité à `Cargo.lock Cargo.toml crates/`), intégrité vérifiée par empreinte SHA-256 avant/après (`c1aecea8…c499d3b` / `701bc7ee…4d6ff016`), rien perdu. **Leçon : vérifier la branche courante AVANT de commencer.** ## Prochaine étape Validation live utilisateur : (1) le desktop ne perd rien, (2) `idea-serve` sert le client web. Si OK → Git merge dans develop (Git refuse de merger sans QA réelle sur les DEUX binaires ; point sensible = workspace `Cargo.toml` members). Débloque ensuite #68 (via `run_embedded`) et #66 (Docker).