chore(wip): état runtime .ideai (conversations, layouts, mémoire, checkpoints)

Persiste l'état runtime : manifestes agents, layouts, permissions, logs et
handoffs de conversations, index mémoire et checkpoints du chantier
orchestrator-designation (restart, backend-compile-fix, qa-verdict) ainsi que
la note conversation-rotation-safety-design.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-20 08:56:32 +02:00
parent 09f536289b
commit 5ef001e7a3
17 changed files with 450 additions and 271 deletions

View File

@ -50,3 +50,9 @@
{"id":"2acee2f9-cf46-4f65-8131-8a66751c55e0","conversation":"08336578-5b47-09d2-2f41-5cc483f101f4","atMs":1781676775264,"source":{"kind":"agent","agentId":"a6ced819-b893-4213-b003-9e9dc79b9641"},"role":"prompt","text":"Tâche QA — tests unitaires LS8-backend (filet humain niveau 3), branche `feature/agent-session-limits`. DevBackend a implémenté (build 0 erreur/0 warning, suites domain/application/app-tauri déjà vertes, non commité).\n\nÀ COUVRIR — nouvelle méthode `SessionLimitService::confirm_human_resume(agent_id, node_id, conversation_id, resets_at_ms: i64)` dans `crates/application/src/agent/session_limit.rs`. Teste via les fakes existants (Clock/Scheduler/EventBus) du fichier `crates/application/tests/session_limit_service.rs` (suis ce style). Cas (cadrage Architect) :\n(a) heure FUTURE ⇒ publie `AgentRateLimited{Some(resets_at_ms)}` puis `AgentResumeScheduled{fire_at_ms == resets_at_ms}` + un ScheduleId armé sur le scheduler.\n(b) heure PASSÉE (resets_at_ms < now) ⇒ clamp : `fire_at_ms == now` (reprise quasi-immédiate). Vérifie l'événement `AgentResumeScheduled` avec fire_at_ms == now.\n(c) DÉDOUBLONNAGE croisé : `confirm_human_resume` APRÈS un `on_rate_limited` déjà armé pour le même agent ⇒ le précédent réveil est désarmé, une seule entrée armée (et l'inverse : `on_rate_limited` après `confirm_human_resume`). Vérifie qu'il n'y a qu'un seul armement actif.\n(d) ANNULABILITÉ : `cancel_resume(agent_id)` après `confirm_human_resume` ⇒ publie `AgentResumeCancelled` et renvoie true (l'armement humain s'annule par la même voie).\n(e) PARITÉ auto/humain : même séquence d'événements qu'`on_rate_limited` cas Scheduled (à reset identique).\n\nÀ COUVRIR — commande `set_resume_at` (app-tauri) si testable au niveau intégration comme `session_limit_wiring.rs` : au minimum le cas `node_for_agent == None` ⇒ erreur NOT_FOUND (pas d'armement orphelin). Si le câblage rend ce test trop lourd (besoin d'une cellule vivante), note-le et concentre-toi sur la couverture application (ae) qui est l'essentiel.\n\nExécute (`cargo test -p application` + `-p app-tauri` si pertinent). RENDS-MOI via idea_reply : commande exacte, résultat réel (passés/échoués), rapport d'erreurs complet si rouge. Si un test révèle un bug (notamment sur le dédoublonnage croisé ou le clamp passé), décris-le précisément (attendu vs obtenu) — je relaierai à DevBackend. Ne commit rien."}
{"id":"a2c0999e-227a-4cfb-99f5-2e8b80ce84f0","conversation":"08336578-5b47-09d2-2f41-5cc483f101f4","atMs":1781676917946,"source":{"kind":"agent","agentId":"aefdbd61-e3d4-4bc1-9f42-c259446a97b5"},"role":"response","text":"QA LS8-backend (filet humain niveau 3) — VERT. Aucun bug d'implémentation trouvé (ni sur le dédoublonnage croisé, ni sur le clamp passé). Rien commité.\n\n## Fichiers de test modifiés (2 — ajouts only, fakes existants réutilisés)\n- `crates/application/tests/session_limit_service.rs` : +6 tests `confirm_human_resume` (style des fakes Clock/Scheduler/EventBus existants).\n- `crates/app-tauri/tests/session_limit_wiring.rs` : +2 tests (précondition NOT_FOUND + parité runtime humaine sur le vrai bus).\n\n## Commandes exactes lancées + résultats réels\n1. `cargo test -p application --test session_limit_service`\n → **15 passed; 0 failed** (10 existants + 5 nouveaux).\n2. `cargo test -p app-tauri --test session_limit_wiring`\n → **4 passed; 0 failed** (2 existants + 2 nouveaux).\n3. `cargo test -p application` (régression complète) → **toutes suites vertes, 0 failed**.\n4. `cargo test -p app-tauri` (régression complète) → **toutes suites vertes, 0 failed**.\n\n## Couverture application (ae) — l'essentiel\n- **(a) heure FUTURE** `confirm_human_resume_future_arms_and_emits_in_order` : exactement 1 `arm(fire_at_ms==resets_at_ms, ResumeAgent{agent,node,conv})`, 1 ScheduleId émis, events `AgentRateLimited{Some(reset)}` PUIS `AgentResumeScheduled{fire_at_ms==reset}` dans cet ordre. ✓\n- **(b) heure PASSÉE** `confirm_human_resume_past_reset_clamps_fire_at_to_now` : `fire_at_ms == now` (clamp anti-passé) ; `AgentRateLimited` garde l'heure brute passée, `AgentResumeScheduled` porte le `now` clampé. ✓\n- **(c) dédoublonnage CROISÉ** (les deux sens) :\n - `confirm_human_resume_after_auto_dedups_single_active_arm` : confirm APRÈS on_rate_limited → l'ancien ScheduleId auto est cancel-é (`cancels == [issued[0]]`), pas d'`AgentResumeCancelled` (silencieux). Unicité prouvée : 1er `cancel_resume`→true, 2e→false. ✓\n - `auto_after_confirm_human_resume_dedups_single_active_arm` : on_rate_limited APRÈS confirm → symétrique, même invariant d'unicité. ✓\n- **(d) ANNULABILITÉ** `cancel_resume_after_confirm_human_resume_returns_true_and_emits_cancelled` : renvoie `true` + publie `AgentResumeCancelled` (même voie que l'auto). ✓\n- **(e) PARITÉ auto/humain** `confirm_human_resume_is_event_for_event_identical_to_auto_scheduled` : à reset futur identique, `bus.events()` ET `scheduler.armed()` strictement égaux entre `confirm_human_resume` et `on_rate_limited`. La source Human vs Structured n'a aucun effet observable. ✓\n\n## Couverture app-tauri `set_resume_at`\n- **NOT_FOUND** `set_resume_at_resolves_no_cell_for_an_agent_without_a_live_session` : ✓ couvert au niveau précondition. NOTE : la commande `#[tauri::command] set_resume_at` exige `State<AppState>`, non constructible hors runtime Tauri — le harnais wiring existant n'invoque jamais les commandes, seulement le service. J'ai donc testé la **précondition exacte** qui produit le NOT_FOUND : sur un `AppState::build` neuf, `structured_sessions.node_for_agent(unknown)` ET `terminal_sessions.node_for_agent(unknown)` renvoient `None` → la branche `ok_or_else(NotFound)` (commands.rs:1420-1428) est prise → aucun armement orphelin. C'est la couverture maximale réaliste sans faire tourner Tauri.\n- **Parité runtime** `confirm_human_resume_arms_a_cancellable_resume_over_the_real_bus` : sur le vrai `TokioBroadcastEventBus`, `confirm_human_resume` publie `AgentRateLimited` puis `AgentResumeScheduled` et l'armement est annulable (`cancel_resume`→true), exactement comme la branche auto déjà testée. ✓\n\n## Observation (non bloquante, pas un bug)\n`confirm_human_resume` est total et défensif : le cas `ResumePlan::HumanFallback` y est inatteignable (`resets_at_ms` toujours `Some`) → traité en no-op via `if let Scheduled`. Conforme au cadrage Architect ; pas de test dédié (branche morte par construction).\n\nBuild app-tauri OK (0 erreur). Rien n'a été commité."}
{"id":"7c627a21-5a9f-470e-9137-a63697ae87da","conversation":"08336578-5b47-09d2-2f41-5cc483f101f4","atMs":1781677172091,"source":{"kind":"agent","agentId":"a6ced819-b893-4213-b003-9e9dc79b9641"},"role":"prompt","text":"Tâche QA — validation LS8-front (formulaire de saisie d'heure, filet humain niveau 3) sur `feature/agent-session-limits`. DevFrontend a implémenté ET ajusté/ajouté des tests (typecheck propre, `npx vitest run src/features/agents/ src/adapters/mock/` = 109 tests verts). Ton rôle : valider la couverture, exécuter, et signaler tout trou ou bug.\n\nPoints à vérifier/exécuter :\n1. Helper pur `timeInputToEpochMs(value, now)` (AgentLimitBadge.tsx) : cas couverts ? « HH:MM » valide → aujourd'hui à cette heure ; instant passé dans la journée → epoch < now (le backend clampe, pas le front) ; malformé/vide/`25:00`/`12:60` → `null`. Ajoute les cas manquants si besoin.\n2. Soumission du formulaire (état suspected SANS heure) ⇒ `onSetResumeAt` / action hook `setResumeAt` appelée avec l'epoch attendu ; bouton désactivé si saisie vide ou `busy` ; saisie malformée (`null`) ne déclenche PAS d'appel.\n3. Action hook `useAgents.setResumeAt(agentId, resetsAtMs)` : délègue bien au port `input.setResumeAt`, aucune mutation optimiste (vérifie que l'état ne bascule QUE sur réception de `agentResumeScheduled`, pas avant). Mock instrumenté `resumeArmings`.\n4. Bascule complète : agent suspected sans heure → submit form → émettre `agentResumeScheduled` (via mock) → le badge passe à l'état nominal (countdown + bouton Annuler), le formulaire disparaît.\n5. Non-régression : tout `src/features/agents/` + `src/adapters/mock/` vert. Confirme le compteur gateways corrigé (14) dans mock.test.ts.\n\nExécute `npx vitest run src/features/agents/ src/adapters/mock/` (+ `tsc --noEmit` si tu veux). RENDS-MOI via idea_reply : commande exacte, résultat réel (passés/échoués), trous comblés (fichiers/tests ajoutés), et tout bug trouvé (attendu vs obtenu, fichier:ligne) — je relaierai à DevFrontend. Ne commit rien."}
{"id":"414e8769-7a3c-4617-b391-f97bc5490877","conversation":"08336578-5b47-09d2-2f41-5cc483f101f4","atMs":1781886707511,"source":{"kind":"agent","agentId":"a6ced819-b893-4213-b003-9e9dc79b9641"},"role":"prompt","text":"QA rapide correctif IdeA Codex structured runtime: j'ai ajouté `PreparedContext.project_root`, relayé ce champ depuis `LaunchAgent`, puis `StructuredSessionFactory` passe `vec![ctx.project_root]` à `CodexExecSession`. `CodexExecSession` ajoute maintenant `--add-dir <project-root>` après `--sandbox workspace-write` et avant le prompt, sans `--ask-for-approval`. Tests ciblés verts: `cargo test -p infrastructure codex_new_conversation_command_carries_exact_args`, `cargo test -p infrastructure codex_resume_command_carries_exact_args`; `cargo check --workspace` vert avec warning préexistant `may_write_directly`. Peux-tu relire le risque principal et indiquer s'il manque un test critique avant rebuild AppImage ?"}
{"id":"0ba164a2-0479-442a-a992-3a6e519a825d","conversation":"08336578-5b47-09d2-2f41-5cc483f101f4","atMs":1781886791342,"source":{"kind":"agent","agentId":"aefdbd61-e3d4-4bc1-9f42-c259446a97b5"},"role":"response","text":"QA rapide terminée.\n\nVerdict : le risque principal est bien le **pont entre le run dir isolé et le vrai project root** pour `codex exec` : si `--add-dir <project-root>` manque, est mal ordonné, ou si `--ask-for-approval` revient, Codex peut soit rester confiné au run dir, soit échouer au démarrage avec largument inconnu. Les deux tests ciblés protègent correctement la composition argv de `CodexExecSession` en neuf et en reprise : ordre exact, `--sandbox workspace-write`, `--add-dir /project/root` avant le prompt, et absence de `--ask-for-approval`.\n\nRelecture du câblage :\n- `PreparedContext` porte maintenant `project_root: String` dans `domain::ports`.\n- `LaunchAgent` le remplit avec `input.project.root.as_str().to_owned()`.\n- `StructuredSessionFactory` passe `vec![ctx.project_root.clone()]` uniquement au bras `StructuredAdapter::Codex`.\n- `CodexExecSession::build_spawn_line` ajoute `--add-dir <root>` après `--sandbox workspace-write`, filtre les racines vides, puis pousse le prompt en dernier.\n\nTest critique manquant ? Pas bloquant pour rebuild AppImage selon moi, parce que le bug runtime immédiat est verrouillé au niveau où largv réel est construit. Le seul test de renfort que jajouterais si on veut fermer complètement la régression est un test **factory-level** : démarrer un profil Codex via `StructuredSessionFactory::start(...)` avec un `PreparedContext { project_root: \"/project/root\" }`, fake CLI enregistreur, `send()`, puis asserter que largv contient bien `--add-dir /project/root`. Les tests actuels instancient `CodexExecSession` directement, donc ils ne prouvent pas explicitement que la factory relaie toujours `ctx.project_root`. Ce nest pas un risque suffisant pour bloquer le rebuild, mais cest le garde-fou le plus utile à ajouter ensuite.\n\nSortie réelle relancée :\n\n`cargo test -p infrastructure codex_new_conversation_command_carries_exact_args` :\n```text\nrunning 1 test\ntest session::tests::codex_new_conversation_command_carries_exact_args ... ok\n\ntest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 220 filtered out; finished in 0.00s\n```\n\n`cargo test -p infrastructure codex_resume_command_carries_exact_args` :\n```text\nrunning 1 test\ntest session::tests::codex_resume_command_carries_exact_args ... ok\n\ntest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 220 filtered out; finished in 0.00s\n```\n\nWarning observé, conforme à ton signalement : `unused import: may_write_directly` dans `crates/application/src/orchestrator/context_guard.rs:29:25`."}
{"id":"6ec1451a-fe4d-4e8d-be02-52425f1f8f88","conversation":"08336578-5b47-09d2-2f41-5cc483f101f4","atMs":1781903727049,"source":{"kind":"agent","agentId":"a6ced819-b893-4213-b003-9e9dc79b9641"},"role":"prompt","text":"Diagnostic demandé par Main : teste uniquement lécriture effective dans le `.git` du projet IdeA, de façon minimale et réversible. Crée un fichier temporaire unique sous `/home/anthony/Documents/Projects/IdeA/.git/`, supprime-le immédiatement si la création réussit, puis rapporte le résultat exact (`WRITE_OK` ou lerreur noyau, notamment `Read-only file system`). Ne lance pas `git add`, `git commit`, ni aucune action Git destructive. Réponds via `idea_reply` si tu reçois ce message comme tâche déléguée."}
{"id":"ccb44f24-80cb-45ee-a724-60313202ae96","conversation":"08336578-5b47-09d2-2f41-5cc483f101f4","atMs":1781903746184,"source":{"kind":"agent","agentId":"aefdbd61-e3d4-4bc1-9f42-c259446a97b5"},"role":"response","text":"Commande exécutée (sans git add/commit ni action Git destructive) : création dun fichier temporaire unique sous `/home/anthony/Documents/Projects/IdeA/.git/`, suppression prévue uniquement en cas de succès.\n\nRésultat :\n```text\ntouch: cannot touch '/home/anthony/Documents/Projects/IdeA/.git/idea-write-test-2-1781903741512743602': Read-only file system\n```\n\nConclusion : écriture refusée par le noyau avec `Read-only file system`. Aucun fichier temporaire na été créé, donc aucune suppression nétait nécessaire."}
{"id":"8bc3c570-3204-444d-ace5-ada62913f082","conversation":"08336578-5b47-09d2-2f41-5cc483f101f4","atMs":1781938370874,"source":{"kind":"agent","agentId":"a6ced819-b893-4213-b003-9e9dc79b9641"},"role":"prompt","text":"Validation QA du chantier `orchestrator-designation` sur la branche courante `feature/orchestrator-designation`.\n\nContexte cycle:\n- Git a décidé de finir ce chantier sur la branche actuelle, sans switch/stash.\n- DevBackend vient de corriger `crates/application/src/orchestrator/context_guard.rs`.\n- Main ne code pas; tu dois valider/qualifier.\n\nHistorique des validations:\nAvant correction DevBackend:\n- `cargo test -p infrastructure input --lib`: OK, 35 passed.\n- `cargo test -p application --test orchestrator_service`: OK, 45 passed.\n- `cd frontend && npx vitest run`: OK, 41 files / 384 tests passed.\n- `cd frontend && npx tsc --noEmit`: OK.\n- `cargo test --workspace`: échouait à la compilation sur `context_guard.rs` (`may_write_directly` 3e arg manquant, `AgentManifest.orchestrator` mal initialisé).\n\nCorrection DevBackend:\n- `ProposeContext` charge `AgentManifest`, récupère `manifest.orchestrator_designation()`, puis appelle `may_write_directly(requester, &GuardedResource::ProjectContext, &designation)`.\n- Tests locaux `context_guard.rs` adaptés au modèle `AgentManifest { version, entries, orchestrator }`.\n- Le `FileGuard` reste un verrou; l'autorisation orchestrateur reste côté domaine.\n\nValidations DevBackend après correction:\n1. `cargo fmt --all && cargo test -p application --test orchestrator_service`\n - OK, `45 passed; 0 failed; 0 ignored`.\n2. `cargo test -p application`\n - OK, suite application verte.\n3. `cargo test --workspace`\n - Compile maintenant plus loin, puis échoue dans `app-tauri`:\n - `app-tauri` lib: `39 passed; 8 failed`.\n - Échecs: `mcp_bridge::tests::end_to_end_over_real_loopback`, `state::bind_endpoint_d1_tests::rebind_after_corpse_socket_succeeds`, et `state::mcp_e2e_loopback_tests::*`.\n - Cause observée: `PermissionDenied` / `Operation not permitted` lors du bind socket sous `/run/user/1000/idea-mcp/*.sock`, ex. `bind test listener: Os { code: 1, kind: PermissionDenied, message: \"Operation not permitted\" }`.\n\nTa mission QA:\n1. Relance les tests pertinents si possible.\n2. Qualifie le résidu `app-tauri`: régression code ou contrainte environnement/sandbox ?\n3. Donne à Main un verdict clair: chantier validable ou correction requise.\n4. Si correction requise, donne le rapport d'erreur exact pour DevBackend.\n5. Si validable sous contrainte, donne la liste de commandes vertes qui font foi et la réserve exacte.\n\nRéponds via `idea_reply` si cette tâche arrive via IdeA."}
{"id":"abed1f56-1094-4d4d-b058-acc2dcd94ca3","conversation":"08336578-5b47-09d2-2f41-5cc483f101f4","atMs":1781938482886,"source":{"kind":"agent","agentId":"aefdbd61-e3d4-4bc1-9f42-c259446a97b5"},"role":"response","text":"Verdict QA: chantier `orchestrator-designation` validable sous contrainte d'environnement. Je ne vois pas de régression fonctionnelle liée à la correction `context_guard.rs`.\n\nCommandes vertes qui font foi:\n- `cargo fmt --all -- --check`: OK, aucune sortie.\n- `cargo test -p application --test orchestrator_service`: OK, `45 passed; 0 failed; 0 ignored`.\n- `cargo test -p application`: OK, suite application complète verte; inclut `orchestrator::context_guard::tests::orchestrator_writes_global_context_directly` et `agent_proposing_global_context_files_a_proposal_not_a_write`.\n- `cargo test -p infrastructure input --lib`: OK, `35 passed; 0 failed; 0 ignored; 187 filtered out`.\n- `cd frontend && npx vitest run`: OK, `41 passed (41)` files, `384 passed (384)` tests.\n- `cd frontend && npx tsc --noEmit`: OK, aucune sortie.\n\nRésidu `app-tauri`:\n- `cargo test -p app-tauri --lib`: ROUGE, `39 passed; 8 failed; 0 ignored`.\n- `cargo test --workspace`: ROUGE sur le même bloc `app-tauri`; la compilation va désormais plus loin et ne bloque plus sur `context_guard.rs`.\n\nÉchecs exacts observés:\n- `mcp_bridge::tests::end_to_end_over_real_loopback`, [crates/app-tauri/src/mcp_bridge.rs:577] : `bind test listener: Os { code: 1, kind: PermissionDenied, message: \"Operation not permitted\" }`.\n- `state::bind_endpoint_d1_tests::rebind_after_corpse_socket_succeeds`, [crates/app-tauri/src/state.rs:4787] : `lay corpse socket: Os { code: 1, kind: PermissionDenied, message: \"Operation not permitted\" }`.\n- `state::mcp_e2e_loopback_tests::{handshake_requester_propagates_over_real_loopback,list_agents_round_trips_over_real_loopback,ask_then_reply_round_trips_inline_over_real_loopback,ask_then_reply_round_trips_inline_over_real_loopback_codex,malformed_jsonrpc_after_handshake_errors_and_server_survives,orphan_reply_is_typed_error_over_real_loopback}`, [crates/app-tauri/src/state.rs:4208] : `M5e needs a real bound listener; bind_endpoint returned None for \"/run/user/1000/idea-mcp/<id>.sock\"`.\n\nQualification du résidu:\n- Contrainte environnement/sandbox, pas régression du chantier. Une sonde Node minimale dans ce même environnement échoue à créer un listener Unix avec `EPERM` même hors `/run/user/1000`:\n - `/run/user/1000/idea-mcp/codex-bind-probe.sock` => `EPERM: listen EPERM: operation not permitted`.\n - `/tmp/codex-bind-probe.sock` => `EPERM: listen EPERM: operation not permitted`.\n- Les 8 tests rouges sont précisément ceux qui exigent un vrai loopback Unix; les tests `mcp_serve_peer_tests` duplex/in-memory et les tests de wiring/domain restent verts.\n\nConclusion: correction DevBackend suffisante pour ce chantier. Pas de correction requise côté `orchestrator-designation`; réserve exacte: la validation globale `cargo test --workspace` reste impossible dans ce sandbox tant que les tests `app-tauri` nécessitant `listen()` sur socket Unix ne peuvent pas binder."}