chore(ideai): carnet de #68, passage en QA et note du faux vert sandbox

Dernier état `.ideai/` du sprint serveur embarqué, séparé du code applicatif
conformément aux précédents `f965f64` / `7fbaa8e` / `5ee25d1`.

- #68 passé en `qa`, pas en `closed` : mergé dans `develop` (`b30c9c7`) et vert,
  mais RIEN n'a été cliqué dans l'app réelle. « Mergé » ne veut pas dire
  « validé » — même distinction que pour #69 et son lot 3.
- Carnet de #68 : périmètre livré, réserve « aucune validation live », et la
  dette identifiée (ordre de `preview_settings` qui verrouille la liste des
  candidats LAN, warning `missingTrustedProxy` inatteignable).
- Mémoire projet : note `sandbox-eperm-bind-false-green-web-server`. Elle
  capitalise le piège qui s'est refermé DEUX FOIS le 2026-07-16 : les sandboxes
  de DevBackend et QA refusent `TcpListener::bind`, donc tout `cargo test` sur
  `web-server`/`app-tauri` y rend un vert qui ne prouve rien. La première fois,
  ce faux vert masquait un vrai bug produit — un serveur embarqué sur port
  éphémère rejetait toutes les requêtes API en 403. La règle qui en sort : aucun
  repli EPERM silencieux, et tout vert sur ces crates doit être produit hors
  sandbox.
- Journal des tâches de fond : complétions enregistrées.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 06:03:11 +02:00
parent f965f64b07
commit a13a6c1801
6 changed files with 161 additions and 9 deletions

View File

@ -7813,10 +7813,62 @@
"ticket_id": "e79249c2-3f08-4fb4-b917-c3d7d1f1ea40",
"conversation_id": "6bc594e8-a37c-0dbd-1de6-6e3b73002cb4"
},
"state": "running",
"state": "completed",
"wakePolicy": "recordOnly",
"createdAtMs": 1784238075328,
"updatedAtMs": 1784238075328,
"updatedAtMs": 1784238314757,
"deadlineMs": null,
"result": {
"outcome": "success",
"finished_at_ms": 1784238314757,
"exit_code": null,
"summary": "Headless rendezvous completed with Final",
"stdout_tail": "#68 est mergé, sans conflit. `develop` est sur **`f965f64`**, vert, arbre propre. La fonctionnalité demandée ce matin est dans `develop`.\n\n## Commits\n\n| Commit | |\n|---|---|\n| `49e1d5a` | `feat(app-tauri)` — controller, commandes, store B2 |\n| `7efa634` | `feat(frontend)` — gateway F1 + panneau Settings Deployment F2 |\n| `b30c9c7` | merge `--no-ff` dans `develop` |\n| `f965f64` | `chore(ideai)` — clôture de #72, à part |\n\nBackend et frontend en deux commits : une branche parce que c'est un lot, deux commits parce que ce sont deux intentions. Pas de rebase, `develop` n'avait pas bougé. Branche supprimée.\n\n## QA refaite hors sandbox\n\nTes quatre chiffres sont confirmés à l'identique : `app-tauri` 43/1 ignored, `web-server` 66, typecheck propre, `vitest` 87 fichiers / 789 tests. Puis re-vérifié sur `develop` après merge — 24 suites Rust, zéro échec, frontend toujours 789.\n\nJ'ai revérifié tes quatre invariants plutôt que de les prendre pour acquis, et ils tiennent tous. `run_embedded_with_core` est le seul appelant — aucune occurrence de `run_embedded` nu dans `app-tauri`, donc le seam de B1 sert bien à ce pour quoi il existe. Aucune fuite d'`EmbeddedServer*`/`ServerExposure*` dans `domain` ni `application`. L'ordre du store est correct : `write(tmp)` → `set_user_only_permissions(tmp)` → `rename`, le fichier final n'est jamais world-readable. Et `stop()` est bien appelé à la sortie d'app (`lib.rs:153`).\n\n**Sur le test `#[ignore]`, j'ai poussé un cran plus loin que ta vérification.** Il est bien préexistant — `#[ignore = \"requires local socket bind permission\"]` dans `mcp_bridge.rs`, présent sur `develop`, fichier que ce lot ne touche pas. Mais comme c'est exactement la classe de test qui nous a piégés deux fois aujourd'hui, je l'ai *lancé* hors sandbox avec `--ignored` plutôt que de raisonner dessus : il passe réellement. Garde d'environnement, confirmée par exécution.\n\nLes trois faits sont dans les messages de commit. Celui qui compte le plus est le brief faux : DevFrontend a intercepté un cadrage qui aurait produit un lot **vert et cassé** — chaque save et chaque start en mode 3 auraient échoué, sans qu'aucun test ne le voie. C'est écrit dans `7efa634`, avec la règle qui en sort : le frontend n'invente jamais une IP, il consomme `candidateLanAddresses`. La dette (ordre de `preview_settings`, code mort `missingTrustedProxy`) est dans `49e1d5a` et dans le merge.\n\n## Un point mineur, pour ton information\n\nLe `0600` est bien posé avant le `rename`, donc ta formulation est exacte. Il reste une fenêtre courte où le **temporaire** existe avec les permissions par défaut de l'umask avant le `chmod`. Le risque est faible — `server-exposure.json` contient des modes, ports, IP et proxies autorisés, aucun secret — et le fichier vit dans l'app-data-dir. Je ne le traite pas et je ne bloque rien ; à verser à la dette de #68 si quelqu'un veut un `OpenOptions::mode(0o600)` à la création.\n\n`develop` est en avance de 25 commits sur `origin/develop`. Aucune action sortante : pas de push, pas de PR.",
"stderr_tail": null
},
"completionDelivered": false
},
{
"id": "dd959500-f6ce-4d28-bcdd-5435da17f9f9",
"projectId": "97b49ac2-8376-4aa3-8ea9-bf3ac81d0023",
"ownerAgentId": "cd0b4cf1-1bef-4fae-ade5-f0a6b49bbaf5",
"kind": {
"kind": "headlessRendezvous",
"requester_agent_id": "a6ced819-b893-4213-b003-9e9dc79b9641",
"target_agent_id": "cd0b4cf1-1bef-4fae-ade5-f0a6b49bbaf5",
"ticket_id": "71016dc7-ab66-46e9-8fbc-cb820e897b06",
"conversation_id": "6bc594e8-a37c-0dbd-1de6-6e3b73002cb4"
},
"state": "completed",
"wakePolicy": "recordOnly",
"createdAtMs": 1784238493799,
"updatedAtMs": 1784238503624,
"deadlineMs": null,
"result": {
"outcome": "success",
"finished_at_ms": 1784238503624,
"exit_code": null,
"summary": "Headless rendezvous completed with Final",
"stdout_tail": "You've hit your session limit · resets 4am (Europe/Paris)",
"stderr_tail": null
},
"completionDelivered": false
},
{
"id": "bf76ce01-9c1c-415d-bfa4-30d4be5d86d9",
"projectId": "97b49ac2-8376-4aa3-8ea9-bf3ac81d0023",
"ownerAgentId": "cd0b4cf1-1bef-4fae-ade5-f0a6b49bbaf5",
"kind": {
"kind": "headlessRendezvous",
"requester_agent_id": "a6ced819-b893-4213-b003-9e9dc79b9641",
"target_agent_id": "cd0b4cf1-1bef-4fae-ade5-f0a6b49bbaf5",
"ticket_id": "98635672-3215-46ed-806c-dd7de084c6eb",
"conversation_id": "6bc594e8-a37c-0dbd-1de6-6e3b73002cb4"
},
"state": "running",
"wakePolicy": "recordOnly",
"createdAtMs": 1784260909376,
"updatedAtMs": 1784260909376,
"deadlineMs": null,
"result": null,
"completionDelivered": false