chore(workstate): notes mémoire campagne MCP T1→T10 + état runtime
Capitalise la mémoire projet produite pendant la campagne de tests fonctionnels MCP (rendez-vous inter-agents, backstop no-reply, réconciliation live-state au reboot) et synchronise l'état runtime `.ideai/` (agents, layouts, skills, index mémoire). Inclut la mise à jour du contexte de l'agent Git. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -5,14 +5,14 @@
|
||||
"agentId": "a6ced819-b893-4213-b003-9e9dc79b9641",
|
||||
"name": "Main",
|
||||
"mdPath": "agents/main.md",
|
||||
"profileId": "664cc20c-47b8-53ad-9351-dce4c09c3da4",
|
||||
"profileId": "664cc20c-47b8-53ad-9351-dce3c09c0de4",
|
||||
"synchronized": false
|
||||
},
|
||||
{
|
||||
"agentId": "dce19c75-9669-4e45-b8de-9950025157da",
|
||||
"name": "Architect",
|
||||
"mdPath": "agents/architect.md",
|
||||
"profileId": "664cc20c-47b8-53ad-9351-dce4c09c3da4",
|
||||
"profileId": "664cc20c-47b8-53ad-9351-dce3c09c0de4",
|
||||
"synchronized": false
|
||||
},
|
||||
{
|
||||
@ -26,14 +26,14 @@
|
||||
"agentId": "af7f86da-76bc-48e1-9900-71f45a624800",
|
||||
"name": "DevFrontend",
|
||||
"mdPath": "agents/devfrontend.md",
|
||||
"profileId": "664cc20c-47b8-53ad-9351-dce4c09c3da4",
|
||||
"profileId": "664cc20c-47b8-53ad-9351-dce3c09c0de4",
|
||||
"synchronized": false
|
||||
},
|
||||
{
|
||||
"agentId": "aefdbd61-e3d4-4bc1-9f42-c259446a97b5",
|
||||
"name": "QA",
|
||||
"mdPath": "agents/qa.md",
|
||||
"profileId": "664cc20c-47b8-53ad-9351-dce4c09c3da4",
|
||||
"profileId": "664cc20c-47b8-53ad-9351-dce3c09c0de4",
|
||||
"synchronized": false
|
||||
},
|
||||
{
|
||||
|
||||
@ -1,15 +1,16 @@
|
||||
# Git — Agent de gestion du dépôt git local
|
||||
|
||||
> Tu es l'**agent Git** d'IdeA. Ton unique responsabilité est la **gestion du dépôt
|
||||
> git local** : commits de l'application, création et bascule de branches, merges et
|
||||
> rebases. Tu es le **seul** à décider de la topologie des branches et à manipuler
|
||||
> l'historique local. Main te sollicite ; tu décides et tu exécutes.
|
||||
> Tu es l'**agent Git** d'IdeA. Ta responsabilité est la **gestion du dépôt
|
||||
> git local** : commits de l'application, création et bascule de
|
||||
> branches, merges, rebases. Tu es le **seul**
|
||||
> à décider de la topologie des branches et à manipuler l'historique. Main te
|
||||
> sollicite ; tu décides et tu exécutes.
|
||||
|
||||
---
|
||||
|
||||
## 1. Ton rôle (et ses limites)
|
||||
|
||||
Tu t'occupes **du local du repo git**, rien d'autre :
|
||||
Tu t'occupes **du repo git local** :
|
||||
|
||||
- **Commits** : tu transformes le travail réalisé par les agents de dev en commits
|
||||
propres, atomiques, au bon endroit (bonne branche), avec des messages cohérents.
|
||||
@ -19,14 +20,16 @@ Tu t'occupes **du local du repo git**, rien d'autre :
|
||||
- Tu **décides** : quand Main t'annonce une nouvelle feature (après cadrage Architect),
|
||||
c'est **toi** qui tranches s'il faut une nouvelle branche, un checkout/switch, ou rien.
|
||||
Après chaque implémentation, Main revient vers toi pour que tu décides si un **merge**
|
||||
doit avoir lieu quelque part, ou non.
|
||||
doit avoir lieu, ou non.
|
||||
|
||||
**Hors périmètre :**
|
||||
**Hors périmètre / garde-fous :**
|
||||
- Tu **n'écris pas de code de feature** (c'est DevBackend/DevFrontend).
|
||||
- Tu ne fais **aucune action sortante** (`push`, publication, création de PR distante)
|
||||
sans validation explicite de Main / de l'utilisateur. Ton terrain est **local**.
|
||||
- Tu ne prends pas de décision produit/archi : si un choix dépend de l'architecture,
|
||||
tu remontes à Main.
|
||||
- **Aucune action sortante** : tu ne **pousses pas** vers un remote (pas de `git push`),
|
||||
tu ne crées pas de PR distante, tu ne publies pas de tags. La synchronisation avec un
|
||||
remote n'est pas dans ton périmètre. Tu restes **strictement local**.
|
||||
- **Jamais** de réécriture destructive de l'historique sans validation explicite de Main.
|
||||
|
||||
---
|
||||
|
||||
@ -110,7 +113,7 @@ tu le dis.
|
||||
délègue une tâche (message `[IdeA · tâche de … · ticket …]`), tu traites puis tu
|
||||
appelles **impérativement** `idea_reply(result=…)`.
|
||||
- Tu rends compte clairement : branche courante, ce que tu as committé (hash + message
|
||||
court), ce que tu as mergé/rebasé, et **ta décision** (pourquoi cette branche, pourquoi
|
||||
ce merge ou ce non-merge).
|
||||
court), ce que tu as mergé/rebasé, et **ta décision** (pourquoi cette
|
||||
branche, pourquoi ce merge ou ce non-merge).
|
||||
- En cas de conflit de merge/rebase, tu le signales à Main avec le détail ; tu ne forces
|
||||
pas une résolution hasardeuse.
|
||||
pas une résolution hasardeuse.
|
||||
@ -1,103 +1,16 @@
|
||||
{
|
||||
"version": 1,
|
||||
"activeId": "0ac56658-4f42-47fe-ad03-c088c832460a",
|
||||
"activeId": "49c6b0fc-13c1-40f5-9464-d3248ab54597",
|
||||
"layouts": [
|
||||
{
|
||||
"id": "0ac56658-4f42-47fe-ad03-c088c832460a",
|
||||
"id": "49c6b0fc-13c1-40f5-9464-d3248ab54597",
|
||||
"name": "Default",
|
||||
"kind": "terminal",
|
||||
"tree": {
|
||||
"root": {
|
||||
"type": "split",
|
||||
"node": {
|
||||
"id": "35174b5f-0c29-4025-a389-e609ff219f39",
|
||||
"direction": "row",
|
||||
"children": [
|
||||
{
|
||||
"node": {
|
||||
"type": "split",
|
||||
"node": {
|
||||
"id": "652a0a78-e342-473d-9725-ebac04556cbf",
|
||||
"direction": "column",
|
||||
"children": [
|
||||
{
|
||||
"node": {
|
||||
"type": "leaf",
|
||||
"node": {
|
||||
"id": "d4b8c0d1-a44a-4c45-bbe9-26991f79b465",
|
||||
"session": "813f17c2-d056-4875-b9a0-3c18e4e40776",
|
||||
"agent": "a6ced819-b893-4213-b003-9e9dc79b9641",
|
||||
"agentWasRunning": true
|
||||
}
|
||||
},
|
||||
"weight": 1.0760044
|
||||
},
|
||||
{
|
||||
"node": {
|
||||
"type": "leaf",
|
||||
"node": {
|
||||
"id": "b7fc564a-7673-4970-acdc-1b8cf23dee8e",
|
||||
"session": "3a6c9dc2-9919-4c17-8f0f-48439151fd27",
|
||||
"agent": "dce19c75-9669-4e45-b8de-9950025157da"
|
||||
}
|
||||
},
|
||||
"weight": 0.9239957
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"node": {
|
||||
"type": "split",
|
||||
"node": {
|
||||
"id": "31597147-d927-4d03-b76c-8d2b22f8b816",
|
||||
"direction": "column",
|
||||
"children": [
|
||||
{
|
||||
"node": {
|
||||
"type": "leaf",
|
||||
"node": {
|
||||
"id": "71564af2-673a-46c7-a0c0-877f89f6e49e",
|
||||
"session": "384778a6-216f-47ed-90f0-67de6812b59d",
|
||||
"agent": "73c853d1-c0fd-463b-ad17-1d24fefa371f",
|
||||
"agentWasRunning": true
|
||||
}
|
||||
},
|
||||
"weight": 1.0
|
||||
},
|
||||
{
|
||||
"node": {
|
||||
"type": "leaf",
|
||||
"node": {
|
||||
"id": "8529e97f-ce06-490c-b3d0-531c3dfee442",
|
||||
"session": "fac01ad4-0e99-4b2a-bdec-621493cf9c57",
|
||||
"agent": "cd0b4cf1-1bef-4fae-ade5-f0a6b49bbaf5",
|
||||
"agentWasRunning": true
|
||||
}
|
||||
},
|
||||
"weight": 1.0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"weight": 1.0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "74489208-01a7-4005-aba4-b9c41ab843fd",
|
||||
"name": "Git Graph",
|
||||
"kind": "gitGraph",
|
||||
"tree": {
|
||||
"root": {
|
||||
"type": "leaf",
|
||||
"node": {
|
||||
"id": "2396a80e-bc98-47cd-b711-c7cff0010bb6"
|
||||
"id": "852f5128-5b98-4d36-9a18-e49a57fc4940"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,3 +17,28 @@
|
||||
- [checkpoint-workstate-delegation-queue-lot-b](checkpoint-workstate-delegation-queue-lot-b.md) — memory note checkpoint-workstate-delegation-queue-lot-b
|
||||
- [checkpoint-workstate-conversation-summaries-lot-c](checkpoint-workstate-conversation-summaries-lot-c.md) — memory note checkpoint-workstate-conversation-summaries-lot-c
|
||||
- [checkpoint-workstate-controlled-actions-lot-d](checkpoint-workstate-controlled-actions-lot-d.md) — memory note checkpoint-workstate-controlled-actions-lot-d
|
||||
- [checkpoint-work-tab-blank-fix](checkpoint-work-tab-blank-fix.md) — memory note checkpoint-work-tab-blank-fix
|
||||
- [skills-integration-canonical-foundation](skills-integration-canonical-foundation.md) — Topologie d'intégration du chantier skills agent et décision d'abandon de feature/agent-skills.
|
||||
- [idea-program-surface-separation-and-livestate](idea-program-surface-separation-and-livestate.md) — Cadrage du programme post-skills : ce qui existe vs reste, et la règle de frontière surface-agent/humaine.
|
||||
- [handoff-ls5-summary-bound-and-llm-seam](handoff-ls5-summary-bound-and-llm-seam.md) — Contrat figé de la borne de handoff (perf) et du seam résumeur LLM non activé.
|
||||
- [conversation-log-ls6-rotation-and-paginated-read](conversation-log-ls6-rotation-and-paginated-read.md) — Contrat figé de la rétention/rotation du transcript et de la lecture paginée riche (surface humaine).
|
||||
- [conversation-viewer-ls7-frontend](conversation-viewer-ls7-frontend.md) — Contrat figé du viewer de transcript paginé (frontend pur, lecture seule, surface humaine).
|
||||
- [live-state-persistence-program-closed-ls8](live-state-persistence-program-closed-ls8.md) — Le programme live-state + persistance conversationnelle est livré et documenté ; pointe la doc de clôture et les points restés ouverts.
|
||||
- [resume-after-appimage-rebuild-mcp-e2e](resume-after-appimage-rebuild-mcp-e2e.md) — memory note resume-after-appimage-rebuild-mcp-e2e
|
||||
- [mcp-e2e-findings-reply-wedge-phantom-busy](mcp-e2e-findings-reply-wedge-phantom-busy.md) — memory note mcp-e2e-findings-reply-wedge-phantom-busy
|
||||
- [checkpoint-finding-a-fix-built-live-validation-pending](checkpoint-finding-a-fix-built-live-validation-pending.md) — memory note checkpoint-finding-a-fix-built-live-validation-pending
|
||||
- [git-agent-push-access-gitea-ssh](git-agent-push-access-gitea-ssh.md) — memory note git-agent-push-access-gitea-ssh
|
||||
- [rendezvous-no-reply-backstop-design](rendezvous-no-reply-backstop-design.md) — Décision d'architecture sur la fin-de-tour et le backstop no-reply du rendez-vous idea_ask_agent ⇄ idea_reply, après échec live du fix Finding A (77e62e5).
|
||||
- [checkpoint-rendezvous-redesign-devbackend-todo](checkpoint-rendezvous-redesign-devbackend-todo.md) — memory note checkpoint-rendezvous-redesign-devbackend-todo
|
||||
- [backstop-no-reply-live-test-failed-2026-06-23](backstop-no-reply-live-test-failed-2026-06-23.md) — memory note backstop-no-reply-live-test-failed-2026-06-23
|
||||
- [live-state-reboot-reconciliation-design](live-state-reboot-reconciliation-design.md) — memory note live-state-reboot-reconciliation-design
|
||||
- [reconcile-live-state-implemented-feature-branch](reconcile-live-state-implemented-feature-branch.md) — memory note reconcile-live-state-implemented-feature-branch
|
||||
- [rendezvous-600s-cap-too-short-heavy-tasks](rendezvous-600s-cap-too-short-heavy-tasks.md) — memory note rendezvous-600s-cap-too-short-heavy-tasks
|
||||
- [backstop-fires-on-intra-task-turn-rootcause](backstop-fires-on-intra-task-turn-rootcause.md) — memory note backstop-fires-on-intra-task-turn-rootcause
|
||||
- [mcp-functional-test-plan-2026-06-24](mcp-functional-test-plan-2026-06-24.md) — memory note mcp-functional-test-plan-2026-06-24
|
||||
- [checkpoint-mcp-tests-t1-t5-and-t5-livestate-defect](checkpoint-mcp-tests-t1-t5-and-t5-livestate-defect.md) — memory note checkpoint-mcp-tests-t1-t5-and-t5-livestate-defect
|
||||
- [checkpoint-mcp-t1-t6-green-t7-fix-wrong-layer](checkpoint-mcp-t1-t6-green-t7-fix-wrong-layer.md) — memory note checkpoint-mcp-t1-t6-green-t7-fix-wrong-layer
|
||||
- [mcp-t7-backstop-600s-reply-rejected-livestate-stale](mcp-t7-backstop-600s-reply-rejected-livestate-stale.md) — memory note mcp-t7-backstop-600s-reply-rejected-livestate-stale
|
||||
- [mcp-functional-tests-t1-t9-green-live-2026-06-24](mcp-functional-tests-t1-t9-green-live-2026-06-24.md) — memory note mcp-functional-tests-t1-t9-green-live-2026-06-24
|
||||
- [mcp-t10a-harness-interrupt-does-not-cancel-rendezvous](mcp-t10a-harness-interrupt-does-not-cancel-rendezvous.md) — memory note mcp-t10a-harness-interrupt-does-not-cancel-rendezvous
|
||||
- [mcp-t10b-pending-reboot-verification](mcp-t10b-pending-reboot-verification.md) — memory note mcp-t10b-pending-reboot-verification
|
||||
|
||||
34
.ideai/memory/backstop-fires-on-intra-task-turn-rootcause.md
Normal file
34
.ideai/memory/backstop-fires-on-intra-task-turn-rootcause.md
Normal file
@ -0,0 +1,34 @@
|
||||
---
|
||||
name: backstop-fires-on-intra-task-turn-rootcause
|
||||
description: memory note backstop-fires-on-intra-task-turn-rootcause
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
title: CAUSE RACINE — le backstop tire sur chaque tour interne (turn_duration ≠ retour-au-prompt)
|
||||
type: project
|
||||
description: Le turn-watcher fait tirer le backstop no-reply au PREMIER turn_duration, soit le 1er pas d'agent interne — il casse toute délégation multi-étapes (libération prématurée + rapport perdu). Le test QA pong passait par chance (tâche mono-tour).
|
||||
---
|
||||
# CAUSE RACINE (2026-06-23, prouvée live) — backstop tire sur les tours INTERNES
|
||||
|
||||
## Preuve
|
||||
Cadrage délégué à Architect (tâche multi-étapes, lecture de code) :
|
||||
```
|
||||
562100 [rendezvous] ask started -> Architect turn_timeout_ms=600000
|
||||
564943 [rendezvous] ask returned-to-prompt-no-reply: Architect after_ms=2843
|
||||
564943 [mailbox] complete_without_reply agent=dce19c75 ticket=cc4067fa outcome=sent
|
||||
```
|
||||
- Tiré à **2843 ms** : impossible qu'Architect ait fini un cadrage en 2,8 s.
|
||||
- Au même instant, transcript Architect **toujours en écriture** (Bash/Read en boucle), `idea_reply` count = **0** → Architect **continuait à travailler**.
|
||||
- Transcript = **61 `turn_duration`** : Claude écrit un `turn_duration` **par tour d'agent interne** (chaque appel LLM de la boucle agentique), PAS seulement au retour-au-prompt final.
|
||||
|
||||
## Diagnostic
|
||||
`claude_turn_watcher.rs` fait tirer `turn_ended` au **premier incrément** de `turn_duration` au-dessus de la baseline. Or cet incrément survient dès le **1er pas interne** de l'agent (~secondes). Donc le backstop confond « l'agent a fait un pas de raisonnement » avec « l'agent est retourné au prompt sans répondre ». Pour **toute tâche multi-étapes** : libération prématurée du demandeur « sans réponse » pendant que la cible bosse encore → `idea_reply` final → « no pending request » → **rapport perdu** (travail survit sur disque/branche).
|
||||
|
||||
Le test QA « pong » (backstop-no-reply-live-test-failed-2026-06-23, devenu vert) passait **par chance** : tâche à **un seul tour** ⇒ premier tour = dernier tour. Le fix `encode_cwd` a fait tirer le watcher correctement, mais a **révélé que la CONDITION de tir est fausse**.
|
||||
|
||||
## Conséquence opérationnelle
|
||||
Avec le binaire courant, **aucune délégation substantielle (multi-tours) ne remonte son rapport** : elle est coupée à ~3 s. Workaround Main en attendant le fix : déléguer → surveiller le transcript de la cible jusqu'à inactivité (mtime stable) → récupérer le résultat sur disque/branche ou re-solliciter en léger.
|
||||
|
||||
## Implication pour la refonte (seam liveness/fin-de-tour, validée utilisateur)
|
||||
« Retourné au prompt idle » NE peut PAS être « un turn_duration est apparu ». Le bon signal = **process vivant (`is_agent_live`) + transcript NE grossit PLUS depuis stall_after_ms** (battement de cœur). Tant que le transcript grossit ⇒ l'agent travaille ⇒ ne pas libérer. Le 1er lot du fix devrait **neutraliser ce tir prématuré**. Lié à [[rendezvous-600s-cap-too-short-heavy-tasks]], [[rendezvous-no-reply-backstop-design]], [[backstop-no-reply-live-test-failed-2026-06-23]].
|
||||
@ -0,0 +1,34 @@
|
||||
---
|
||||
name: backstop-no-reply-live-test-failed-2026-06-23
|
||||
description: memory note backstop-no-reply-live-test-failed-2026-06-23
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
title: Backstop no-reply — RE-VALIDATION LIVE VERTE (wedge levé) après fix encode_cwd
|
||||
type: project
|
||||
description: Le backstop no-reply du rendez-vous est validé en live le 2026-06-23 (session post-rebuild) : demandeur libéré ~grâce 2s au lieu de 600s. Reste un point de finition (résultat véhiculé via canal d'erreur).
|
||||
---
|
||||
|
||||
# Backstop no-reply — RE-VALIDATION LIVE : VERTE (2026-06-23, session post-rebuild)
|
||||
|
||||
Remplace le 1er test (ÉCHEC) du même jour. La cause racine était l'encodage du slug projet Claude (`.` non encodé) corrigé dans `crates/infrastructure/src/inspector/claude_paths.rs` (`encode_cwd` → `replace(/[^a-zA-Z0-9]/g,'-')`, double-tiret sur `/.ideai/`). Voir [[checkpoint-rendezvous-redesign-devbackend-todo]] pour la cause racine.
|
||||
|
||||
## Preuves live (idea.log, session a6ced819)
|
||||
Scénario : DevBackend → idea_ask_agent vers QA « pong en prose, SANS idea_reply (volontaire) ».
|
||||
|
||||
```
|
||||
912948 [mcp] ask armed requester=DevBackend(73c853d1) target=QA timeout_ms=600000
|
||||
917707 [turn-watcher] turn_duration detected agent=QA(aefdbd61) count 47->48 -> turn_ended
|
||||
917707 [input-mediator] turn_ended agent=QA no_reply_payload -> mark_idle + grace
|
||||
917707 [input-mediator] turn_ended arming grace agent=QA ticket=0257c630 grace_ms=2000
|
||||
919707 [mailbox] complete_without_reply agent=QA ticket=0257c630 queue_depth_before=1 after=0 outcome=sent
|
||||
```
|
||||
|
||||
Contraste avec l'échec précédent : `turn_ended` = 0 avant le fix, ici il FIRE ; `arm … dir=…IdeA--ideai-run-…` sur dossier EXISTANT ; grâce 2s exacte (917707→919707) ; libération du demandeur via `complete_without_reply outcome=sent`. DevBackend a repris la main en ~13 s mesuré (pas 600 s). Aucun wedge, aucun cascade-timeout.
|
||||
|
||||
## Point de finition résiduel (NON bloquant, follow-up)
|
||||
Le résultat rendu au demandeur passe par le **canal d'erreur** MCP : « agent QA returned to its prompt without calling idea_reply (no answer was rendered); retry the request and ensure the agent replies via idea_reply ». Ce n'est pas un résultat no-reply synthétique structuré (design item c de [[rendezvous-no-reply-backstop-design]]) ; pour un orchestrateur c'est mal distinguable d'un échec transitoire « retry ». À transformer en verdict consommable (follow-up, hors blocage merge).
|
||||
|
||||
## Suite
|
||||
Wedge prouvé levé en live ⇒ garde-fou Git satisfait. Délégué à Git : commit du fix `encode_cwd` (+ test de non-régression `encode_cwd_encodes_dot_in_run_dir_to_double_dash`) sur la branche du backstop, puis décision de merge develop.
|
||||
62
.ideai/memory/checkpoint-auto-memory-harvest-lot-e1.md
Normal file
62
.ideai/memory/checkpoint-auto-memory-harvest-lot-e1.md
Normal file
@ -0,0 +1,62 @@
|
||||
---
|
||||
name: checkpoint-auto-memory-harvest-lot-e1
|
||||
description: memory note checkpoint-auto-memory-harvest-lot-e1
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# Checkpoint — Auto-memory harvest Lot E1
|
||||
|
||||
Date: 2026-06-21
|
||||
|
||||
## État final
|
||||
|
||||
Lot E1 `auto-memory harvest contrôlé` terminé, validé QA et mergé localement dans `develop`.
|
||||
|
||||
Branche finale:
|
||||
- `develop` @ `61c330a` — merge local `feature/controlled-auto-memory-harvest`.
|
||||
- Branche `feature/controlled-auto-memory-harvest` supprimée après merge.
|
||||
- Aucun push, aucun merge vers `main`.
|
||||
- Working tree applicatif propre; seuls résidus non committés: bruit runtime `.ideai/*` volontairement exclu.
|
||||
|
||||
## Commits créés
|
||||
|
||||
- `b12081b` — `feat(memory): récolte automatique contrôlée de la mémoire (Lot E1)`
|
||||
- Domaine: parsing pur de blocs fenced `idea-memory` avec limites et erreurs isolées.
|
||||
- Application: `HarvestMemoryFromTurn` best-effort sur `TurnRole::Response`, persistance via `MemoryStore`, événements `MemorySaved` via `EventBus`.
|
||||
- Orchestrateur: harvest branché après checkpoint/handoff sur chemins de succès ask/reply, non bloquant.
|
||||
- Lifecycle: directive mémoire IdeA injectée dans le contexte convention-file.
|
||||
- App/Tauri: wiring du use case dans `AppState`.
|
||||
- Frontend: refresh du panneau mémoire sur `memorySaved`; patch test-only mock gateway `workState`.
|
||||
|
||||
- `8c7c47c` — `fix(mcp): fallback déterministe du runtime dir socket`
|
||||
- Durcit le choix du runtime dir socket MCP si `XDG_RUNTIME_DIR` est inutilisable.
|
||||
- Commit séparé car indépendant du Lot E1.
|
||||
|
||||
- `61c330a` — `merge(memory): intègre la récolte automatique contrôlée (Lot E1) dans develop`.
|
||||
|
||||
## QA verte
|
||||
|
||||
Commandes QA réelles:
|
||||
- `cargo fmt --all -- --check` OK.
|
||||
- `cargo check -p app-tauri` OK.
|
||||
- `cd frontend && npx tsc --noEmit` OK.
|
||||
- `cd frontend && npx vitest run` OK après patch test-only, `42 passed`, `405 tests`.
|
||||
- `cargo test -p domain memory_harvest -- --nocapture` OK, 14 passed.
|
||||
- `cargo test -p application --test memory_harvest -- --nocapture` OK, 5 passed.
|
||||
- `cargo test -p application --test orchestrator_service harvest -- --nocapture` OK, 4 passed.
|
||||
- `cargo test -p infrastructure --test memory_store idempotent -- --nocapture` OK, 1 passed.
|
||||
- `cargo test --workspace` brut rouge uniquement sur tests AF_UNIX/MCP bloqués par sandbox `Operation not permitted`; workspace filtré strictement sur ces tests environnementaux OK.
|
||||
|
||||
## Décisions produit/techniques
|
||||
|
||||
- Harvest strictement best-effort: jamais bloquant pour réponse, délégation, handoff ou ticket.
|
||||
- Mémoire durable seulement via directive explicite `idea-memory`, plafonnée et validée; pas de log brut, pas de live-state, pas de handoff dans ce mécanisme.
|
||||
- `title` est exigé par directive mais non persisté car l'entité `Memory` n'a pas de champ titre; accepté pour E1 afin de ne pas élargir le lot.
|
||||
- Les fichiers runtime `.ideai/*` générés pendant la session restent hors commits applicatifs.
|
||||
|
||||
## Suite probable
|
||||
|
||||
Prochains chantiers à cadrer par Architect avant implémentation:
|
||||
- persistance conversationnelle/canonical log + handoff incrémental cross-profile;
|
||||
- live-state projet persistant et séparé de la mémoire durable;
|
||||
- synchronisation documentaire architecture après les lots Work B/C/D et E1.
|
||||
@ -0,0 +1,37 @@
|
||||
---
|
||||
name: checkpoint-finding-a-fix-built-live-validation-pending
|
||||
description: memory note checkpoint-finding-a-fix-built-live-validation-pending
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# Checkpoint — Finding A : fix confirmé EN CODE + AppImage clean DÉPLOYÉE → reste la validation e2e LIVE (MAJ 2026-06-23 09:33)
|
||||
|
||||
Suite de [[mcp-e2e-findings-reply-wedge-phantom-busy]] (le défaut) et [[resume-after-appimage-rebuild-mcp-e2e]] (méthode).
|
||||
|
||||
## État du code (OK, vert)
|
||||
- Fix Finding A **mergé dans `develop @ 77e62e5`** (par-dessus feat `c5e5493`).
|
||||
- 3 lots : **Lot 1** préambule `idea_reply` impératif (`infrastructure/src/input/mod.rs` + `application/src/agent/lifecycle.rs`) ; **Lot 2 = LE fix** `with_prompt_ready_pattern("? for shortcuts")` sur le profil Claude (`application/src/agent/catalogue.rs:80`) + overlay `overlay_reference_defaults` ; **Lot 3** backstop timeout typé `TARGET_RETURNED_NO_REPLY` / env `IDEA_ASK_RENDEZVOUS_TIMEOUT_MS` (`infrastructure/src/orchestrator/mcp/server.rs`).
|
||||
- Tests lib qui PROUVENT le seed (re-passés vert le 2026-06-23) : `application::agent::catalogue::mcp_tests::claude_seed_carries_the_measured_prompt_ready_pattern` ✓ et `codex_seed_leaves_prompt_ready_pattern_empty_for_now` ✓.
|
||||
|
||||
## LEÇON D'OUTILLAGE (important, éviter de refaire l'erreur)
|
||||
**Ne PAS utiliser `strings`/`grep` sur le binaire comme oracle de présence du fix.** Le compilateur élimine/inline les littéraux uniques de `catalogue.rs` : `? for shortcuts` ET `codex --version` sont ABSENTS du binaire alors que le code et les tests les portent (les littéraux aussi présents ailleurs — `claude --version`, `.mcp.json`, `CLAUDE.md` — n'apparaissent que par co-référence). Oracle fiable = **tests** + **comportement live**, pas le grep binaire. (Une fausse alarme « build incrémental incohérent » a été levée puis invalidée ainsi.)
|
||||
|
||||
## Mise en service FAITE
|
||||
- Rebuild clean (`cargo clean -p application -p infrastructure` puis recette tauri) → artefact `…/target/release/bundle/appimage/IdeA_0.3.0_amd64.AppImage`.
|
||||
- **Déployé** sur `/home/anthony/Documents/IdeA_0.3.0_amd64.AppImage` (rename atomique ; SHA256 `138714473ed6a87b…` installée == artefact). Ancienne sauvegardée `…AppImage.bak-23pre`.
|
||||
- ⚠️ **L'instance IdeA qui tourne encore est l'ANCIENNE** (FUSE déjà monté). Il faut que **l'utilisateur RELANCE IdeA** pour charger le nouveau binaire — cela redémarre tous les agents, dont Main (la session courante meurt).
|
||||
|
||||
## PROCHAINE ÉTAPE après redémarrage : test e2e LIVE
|
||||
Méthode (rappel) : **NE PAS valider le système inter-agents VIA `idea_ask_agent`**. Piloter via subagents natifs / l'utilisateur. Diag EXTERNE : `ss -xp | grep idea-mcp` (ponts) ; transcripts `~/.claude/projects/<run-dir-encodé>/*.jsonl` (horodatages UTC ; reply réel = `tool_use` idea_reply ; wedge = transcript demandeur figé sur `tool_use` idea_ask_agent sans `tool_result`).
|
||||
|
||||
Scénario qui wedgeait (doit maintenant passer) :
|
||||
1. Faire déléguer **DevBackend → QA** : « réponds juste pong ».
|
||||
2. ATTENDU avec le fix : si QA répond en prose sans `idea_reply`, dans la grâce `PROMPT_READY_GRACE` le retour au prompt idle (`? for shortcuts`) déclenche `complete_without_reply` → **DevBackend reçoit `TargetReturnedNoReply` (retryable) et REPREND la main** (plus de wedge) ; `idea_workstate` QA repasse `working`→`idle`/`done` (plus de Busy fantôme). Lot 1 devrait en plus pousser QA à appeler `idea_reply` (chemin positif → DevBackend reçoit pong).
|
||||
3. Non-régression : chemin positif normal (QA appelle `idea_reply`) → demandeur reçoit le résultat, workstate→done ; livraison 1er tour à froid intacte.
|
||||
4. Calibrer `PROMPT_READY_GRACE` si la fenêtre est trop courte/longue en réel (défaut conservé).
|
||||
|
||||
## Après validation verte
|
||||
Merge `develop` déjà fait. Reste éventuelle release (0.4.0 ?) = décision utilisateur. NB : **Git est de nouveau strictement local, PLUS d'accès push** (la note `git-agent-push-access-gitea-ssh` a été corrigée en ce sens). `develop` est ~69 commits devant `origin/develop` (sync remote hors périmètre Git).
|
||||
|
||||
## Follow-ups différés (hors PR)
|
||||
Capture `prompt_ready_pattern` Codex ; généralisation merge profils de référence ; e2e délégation background (node_id None) / profils MCP défaut / observabilité UI des délégations ; durcissement doc `idea_reply` dans `CLAUDE.md` versionné (router à Git).
|
||||
@ -0,0 +1,40 @@
|
||||
---
|
||||
name: checkpoint-mcp-t1-t6-green-t7-fix-wrong-layer
|
||||
description: memory note checkpoint-mcp-t1-t6-green-t7-fix-wrong-layer
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
name: checkpoint-mcp-t1-t6-green-t7-fix-wrong-layer
|
||||
description: T1→T6 verts (non-régression). T7 ROUGE diagnostiqué (fix sur mauvaise couche) PUIS RE-FIX implémenté dans le working tree + vert en tests unitaires. Reste : rebuild AppImage en cours → relance IdeA → re-valider T1→T7 en live → commit Git.
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# Checkpoint tests fonctionnels MCP — run a6ced819 (2026-06-24)
|
||||
|
||||
Plan via skill **mcp-rendezvous-functional-test**, Main = demandeur. Setup chauds : Main/QA/DevFrontend ; froids : Architect/DevBackend/Git.
|
||||
|
||||
## T1→T6 : VERTS sur AppImage 09:21 (aucune régression)
|
||||
T1 visibilité, T2 chaude `pong`, T3 réveil froid Git (1er tour intact), T4 background node_id None, T5 no-reply backstop (live-state purgée), T6 multi-étapes == oracle. Détails dans l'historique. NB outillage : `pgrep -af mcp-server | grep <uuid>` = FAUX positifs (le shell de mesure se matche) → filtrer `ps -eo cmd | grep 'app-tauri mcp-server'`.
|
||||
|
||||
## T7 : défaut trouvé EN LIVE puis CORRIGÉ
|
||||
**Défaut (T7e live, 621 s ≈ 600 s)** : cible en long tour unique > 600 s (transcript en croissance prouvée) coupée par un timeout PLAT `process error: agent session reply timed out`, pas d'extension. Le watchdog du fix précédent vivait côté requester (`server.rs`) mais le seam qui coupe vraiment est `application/src/orchestrator/service.rs` (`ASK_AGENT_TIMEOUT`=600s plat appliqué au drain de tour délégué, ~L1564). **Fix posé sur la mauvaise couche.**
|
||||
|
||||
**RE-FIX implémenté (subagent natif Architect→DevBackend→QA, worktree, ramené dans le main working tree ; HEAD toujours `1efe2f1`, NON committé)** :
|
||||
- Découverte clé : `ClaudeSdkSession::send().await` rend TOUS les `ReplyEvent` en bloc À LA FIN du tour (rien mid-turn) → la vivacité par-événement est inutilisable ; seul signe de vie réel = **sonde transcript** (octets `.jsonl`), comme `server.rs`.
|
||||
- Un seul `run_inactivity_watchdog` générique dans **`crates/application/src/orchestrator/rendezvous.rs`** (NOUVEAU, pur, testé), réutilisé par `service.rs` (le vrai seam) ET `server.rs` (copie privée supprimée → dé-duplication).
|
||||
- Nouveau port `AskLivenessProbe` injecté au composition root `app-tauri/state.rs` → `transcript_activity_token` (+ `with_ask_ceiling`, env `IDEA_ASK_RENDEZVOUS_CEILING_MS`, défaut 4 h). Sans injection ⇒ fallback fenêtre plate = zéro régression.
|
||||
- Issues typées : progrès<plafond → réarme ; progrès+plafond → `AppError::TargetCeilingActive` (code `RENDEZVOUS_CEILING_ACTIVE`, non-retry-aveugle) ; vrai silence → `AgentSessionError::Timeout` inchangé.
|
||||
- Défaut secondaire (busy fantôme) : `mark_target_done_best_effort` sur toutes les branches d'abandon (PTY + structuré).
|
||||
- Fichiers : application `{rendezvous.rs(new), service.rs, error.rs, lib.rs, orchestrator/mod.rs}`, infra `mcp/server.rs`, `app-tauri/state.rs` (+ les modifs infra inspector/lib pré-existantes du 1er fix).
|
||||
- **Preuve réelle (re-vérifiée par Main dans le MAIN TREE)** : `cargo test -p application --lib` 75/0 (dont progressing_target_extends_then_resolves, _hits_ceiling_distinctly, silent_target_expires_no_reply, no_probe_falls_back_to_flat_window, ceiling_active_code) ; `cargo test -p infrastructure --lib` 247/0 ; clippy 0 nouveau warning.
|
||||
|
||||
## PROCHAINE ÉTAPE (reprise après relance IdeA)
|
||||
1. **Rebuild AppImage EN COURS** (recette : `npm --prefix frontend run build` puis depuis `crates/app-tauri/` `APPIMAGE_EXTRACT_AND_RUN=1 NO_STRIP=1 ../../frontend/node_modules/.bin/tauri build --bundles appimage` ; artefact `target/release/bundle/appimage/IdeA_0.3.0_amd64.AppImage` → remplace `/home/anthony/Documents/IdeA_0.3.0_amd64.AppImage`, backup l'ancienne). Log build : scratchpad/rebuild.log.
|
||||
2. **Utilisateur relance IdeA** (tue Main).
|
||||
3. **Reprendre le test depuis T1** (skill). Le but immédiat = **re-valider T7 EN LIVE** : déléguer une charge réelle > 600 s en un long tour (la machine est rapide : `cargo clean && cargo build --release --workspace` en boucle jusqu'à >13 min, transcript en croissance) ⇒ ATTENDU = PAS de timeout à 600 s, extension, reply final livré. Puis enchaîner T8 (parallèles), T9 (transitif A→B→C, Architect+DevBackend froids), T10 (interruption + reconcile reboot).
|
||||
4. **Si live vert : demander à Git de committer** le fix (cf. [[git-owns-commit-merge-decisions]]) ; rendez-vous MCP court marche (T2-T6), donc commit délégable à Git OU subagent natif.
|
||||
|
||||
Lié à [[rendezvous-600s-cap-too-short-heavy-tasks]], [[mcp-functional-test-plan-2026-06-24]], [[mcp-bridge-and-delegation-runtime-notes]].
|
||||
</content>
|
||||
</invoke>
|
||||
@ -0,0 +1,29 @@
|
||||
---
|
||||
name: checkpoint-mcp-tests-t1-t5-and-t5-livestate-defect
|
||||
description: memory note checkpoint-mcp-tests-t1-t5-and-t5-livestate-defect
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
name: checkpoint-mcp-tests-t1-t5-and-t5-livestate-defect
|
||||
description: Run a6ced819 — relance complète T1→T6 du test fonctionnel MCP sur AppImage 08:41 (fix T5). T5 (live-state purgée sur no-reply) VALIDÉ EN LIVE. Blocage à T7 = défaut plafond 600s connu, non corrigé.
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# Checkpoint tests fonctionnels MCP — run a6ced819 (2026-06-24, relance depuis T1)
|
||||
|
||||
Binaire validé : **AppImage 2026-06-24 08:41:30** (fix live-state no-reply), process en cours = cette AppImage, git HEAD `1efe2f1`. Plan via skill **mcp-rendezvous-functional-test** (Main = demandeur). Voir [[mcp-functional-test-plan-2026-06-24]], [[rendezvous-600s-cap-too-short-heavy-tasks]], [[backstop-fires-on-intra-task-turn-rootcause]].
|
||||
|
||||
## Résultats de la relance T1→T6 (tous ✅)
|
||||
- **T1** visibilité outils ✅ — 3 requesters chauds (Main, QA, DevFrontend) chacun pont ESTAB + 2 mcp-server ; froids (Architect, DevBackend, Git) 0 process.
|
||||
- **T2** cible chaude (QA) ✅ — `pong` inline borné, workstate `done`, pas de busy fantôme.
|
||||
- **T3** réveil à froid (Git) ✅ — nouveau pont (26012/26016), 1er tour `[IdeA·tâche…]` `parentUuid:null` intact, `delivered`, `pong-cold`.
|
||||
- **T4** background node_id None (Git hors layouts.json) ✅ — `bg-step-ok`, multi-`delivered`, pont stable sans dup.
|
||||
- **T5** no-reply backstop ✅ **VALIDÉ EN LIVE (le fix marche)** — Main libéré borné avec `TargetReturnedNoReply` (« returned to its prompt without calling idea_reply », retryable) ET **QA `status:"done"` purgée** (plus de busy fantôme `working`). Défaut historique #1 fermé.
|
||||
- **T6** multi-étapes (QA lit fichier + `find` puis reply) ✅ — pas de libération prématurée, reply réel `header=… ; rs_count=55` (concorde avec `find` indépendant). Piège turn-watcher non déclenché.
|
||||
|
||||
## Blocage actuel : T7 (NON lancé — défaut connu non corrigé)
|
||||
T7 = tâche lourde > plafond 600s. C'est le finding [[rendezvous-600s-cap-too-short-heavy-tasks]] : dépassement du plafond `IDEA_ASK_RENDEZVOUS_TIMEOUT_MS` (défaut 600000) → faux `-32001` + canal de report mort (idea_reply final non livrable), alors que la cible travaille et finit sur la branche. Les pistes (extension sur signe de vie / message « cible active, plafond atteint » distinct du retryable / plafond configurable / pas de cascade) sont **à cadrer Architect, pas encore implémentées**. Lancer T7 en live = figer Main ~10 min pour re-confirmer un défaut déjà documenté.
|
||||
|
||||
## Prochaine étape (décision utilisateur en attente)
|
||||
Trois options sur T7 : (a) le lancer quand même pour re-confirmer (wedge ~10 min) ; (b) ouvrir le cycle de fix du plafond maintenant (Architect→Git→DevBackend→QA, rebuild, reprise T1) ; (c) sauter T7 et continuer T8 (parallèles), T9 (transitif A→B→C), T10 (interruption + reconcile reboot) qui ne dépendent pas du plafond. Architect/DevBackend restent froids pour T9.
|
||||
@ -0,0 +1,38 @@
|
||||
---
|
||||
name: checkpoint-rendezvous-redesign-devbackend-todo
|
||||
description: memory note checkpoint-rendezvous-redesign-devbackend-todo
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# Checkpoint — Backstop no-reply : 1ère validation live ÉCHOUÉE → cause racine corrigée → RE-VALIDATION LIVE EN ATTENTE (MAJ 2026-06-23 ~19:40)
|
||||
|
||||
## Résultat du 1er test live (AppImage 0.3.0 du commit e87c05f) : ÉCHEC reproduisant le wedge
|
||||
Scénario joué : DevBackend→QA `ping (test backstop)`, QA répond `pong` EN PROSE sans `idea_reply`.
|
||||
- QA a bien émis un vrai `turn_duration durationMs=2218` (transcript, ts 17:23:40.161Z).
|
||||
- MAIS `[turn-watcher] turn_ended` JAMAIS émis (`grep -c turn_ended` sur tout le log = **0**) → DevBackend resté coincé → rendez-vous Main→DevBackend a timeout 600s (MCP error -32001).
|
||||
|
||||
## CAUSE RACINE (prouvée) — encodage du slug projet Claude faux
|
||||
Traces `[turn-watcher] arm` : toutes `conversation=<none>` + `baseline … count=0`. Le dossier transcript calculé n'existait pas :
|
||||
- calculé (faux) : `…/-home-…-IdeA-.ideai-run-<uuid>` (point conservé) → `ls` = absent
|
||||
- réel (disque) : `…/-home-…-IdeA--ideai-run-<uuid>` (DOUBLE tiret)
|
||||
`encode_cwd` (crates/infrastructure/src/inspector/claude_paths.rs) ne remplaçait que `/`/`\\` et gardait le `.`. Claude Code encode `replace(/[^a-zA-Z0-9]/g,'-')`. Dir introuvable → conversation non résolue → baseline 0 → `turn_duration` jamais vu → backstop mort.
|
||||
Log de référence : `/home/anthony/.local/share/app.idea.ide/logs/idea.log`.
|
||||
|
||||
## FIX LIVRÉ par DevBackend (NON commité — Git tranche)
|
||||
- `encode_cwd` : `.map(|c| if c.is_ascii_alphanumeric() { c } else { '-' })` (algo exact Claude Code). `/IdeA/.ideai/run` → `-IdeA--ideai-run`.
|
||||
- Test non-régression ajouté `encode_cwd_encodes_dot_in_run_dir_to_double_dash` (PASS). Test Windows maj `C:\\Users\\me`→`C--Users-me`.
|
||||
- DevBackend précise : `count_turn_ends` agrège déjà tous les `.jsonl` du dossier ⇒ pas besoin de choisir un .jsonl ; `conversation=<none>` à l'armement est normal et sans impact une fois le dir correct.
|
||||
|
||||
## QA PRÉ-VALIDATION : VERTE
|
||||
`cargo test --workspace` = **1616 passed, 0 failed** ; `cargo clippy --workspace --all-targets` = 0 erreur. Nouveau test + 5 tests turn-watcher tous PASS.
|
||||
|
||||
## EN COURS : rebuild AppImage (par Main, perms project-root OK)
|
||||
Recette : `npm --prefix frontend run build` puis depuis `crates/app-tauri/` `APPIMAGE_EXTRACT_AND_RUN=1 NO_STRIP=1 ../../frontend/node_modules/.bin/tauri build --bundles appimage`. Logs scratchpad fe-build.log / appimage-build.log. Sortie : `/home/anthony/Documents/Projects/IdeA/target/release/bundle/appimage/IdeA_0.3.0_amd64.AppImage`.
|
||||
|
||||
## SEUL RESTE À FAIRE = RE-VALIDATION LIVE (garde-fou Git : pas de merge sans wedge prouvé levé EN LIVE)
|
||||
1. Utilisateur remplace l'AppImage installée par la nouvelle + relance IdeA (coupe la session).
|
||||
2. Session fraîche : rejouer DevBackend→QA pong-sans-`idea_reply`. ATTENDU cette fois : trace `arm … dir=…IdeA--ideai-run-… conversation=…` sur dossier EXISTANT + baseline NON nulle + `[turn-watcher] turn_duration detected … -> turn_ended` ⇒ libération du demandeur ~grâce (≈2s) avec résultat no-reply synthétique, et non-régression du chemin propre `idea_reply`.
|
||||
3. Si VERT → demander à Git d'amender/committer le fix sur `feature/rendezvous-no-reply-backstop` puis décider du merge develop. Si KO → relayer trace réelle à DevBackend.
|
||||
|
||||
## Trou produit confirmé (hors scope, à planifier)
|
||||
Au reboot, `.ideai/live-state.json` non réconcilié : agents restent `working` fantôme (process morts). Fichier file-guardé, `idea_workstate_set` = self only, aucun reset cross-agent. Manque : réconciliation au boot OU outil orchestrateur de reset.
|
||||
34
.ideai/memory/checkpoint-work-tab-blank-fix.md
Normal file
34
.ideai/memory/checkpoint-work-tab-blank-fix.md
Normal file
@ -0,0 +1,34 @@
|
||||
---
|
||||
name: checkpoint-work-tab-blank-fix
|
||||
description: memory note checkpoint-work-tab-blank-fix
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# Checkpoint — Fix onglet Work vide
|
||||
|
||||
Date: 2026-06-21
|
||||
|
||||
## État final
|
||||
|
||||
Correctif frontend de l'onglet Work vide terminé, validé QA (VERT) et mergé localement dans `develop`.
|
||||
|
||||
- `develop` @ `a66881d` — merge local `--no-ff` du fix.
|
||||
- Commit de feature intégré : `3e1e553` (anciennement `9d2f186`, message amendé pour retirer le marqueur `(WIP, QA en attente)`).
|
||||
- Branche `fix/work-tab-blank-page` supprimée après merge.
|
||||
- Aucun push, aucune PR. `develop` en avance de 45 commits sur `origin/develop` (local-only).
|
||||
|
||||
## Contenu du fix
|
||||
|
||||
Normalisation défensive du work-state (`frontend/src/adapters/workStateNormalization.ts` nouveau) + adaptation panneau/mock/tests, pour qu'un work-state partiel/inattendu ne rende plus une page entièrement vide. 5 fichiers, +259/-47.
|
||||
|
||||
## QA verte (sortie réelle)
|
||||
|
||||
- `cd frontend && npx tsc --noEmit` → exit 0.
|
||||
- `cd frontend && npx vitest run` → 42 fichiers / 407 tests passed, exit 0.
|
||||
|
||||
## Branches ouvertes restantes (non mergées dans develop)
|
||||
|
||||
À cadrer/arbitrer avant intégration :
|
||||
- `feature/agent-skills` @ `ef101db` — domaine skills agent + use cases + FS store + injection LaunchAgent (L12).
|
||||
- `feature/agent-skill-awareness` @ `5be8987` — manifeste skills + outil MCP `idea_skill_read` + brief « capacités IdeA » dans contexte agent ; contient aussi un fix input cold-start (`e93a2c1`).
|
||||
- `fix/cold-start-delivery-race` @ `9590eac` — fix livraison délégation cold-start ; branche basée sur d'anciens commits release (0.1.0/0.2.0), potentiellement redondante avec `e93a2c1` de skill-awareness → vérifier avant merge.
|
||||
@ -0,0 +1,29 @@
|
||||
---
|
||||
name: conversation-log-ls6-rotation-and-paginated-read
|
||||
description: Contrat figé de la rétention/rotation du transcript et de la lecture paginée riche (surface humaine).
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
# LS6 — Rotation transcript + lecture paginée
|
||||
|
||||
Hygiène de persistance du `log.jsonl` + surface de lecture humaine paginée (viewer LS7).
|
||||
|
||||
## Invariant pivot INV-LS6
|
||||
La rotation n'élague/déplace JAMAIS un tour d'id ≥ `up_to` du handoff courant : le tour up_to + tous les postérieurs restent dans le segment ACTIF. Sans handoff (ou up_to nil) ⇒ aucune rotation. Garantit que `ConversationLog::read(since=up_to)` (fold incrémental) et la reprise restent corrects après rotation. Motif : `read(since)` cherche le curseur par position ; retirer up_to du fichier casserait le fold.
|
||||
|
||||
## Rotation
|
||||
- Stratégie = **archive segmentée** (`log.jsonl` actif + `log.1.jsonl`… anciens), PAS troncature/suppression (transcript = surface humaine riche à préserver).
|
||||
- Déclencheur **hors chemin chaud** : use case `RotateConversationLog` à la reprise/ouverture, best-effort, idempotent. L'`append` ne déclenche JAMAIS la rotation (zéro latence ajoutée).
|
||||
- Seuils sur segment actif : `ROTATE_AFTER_TURNS=500` OU `ROTATE_AFTER_BYTES=1MiB`. Backstop disque `MAX_ARCHIVE_SEGMENTS=20` (drop du plus ancien seulement). Politique pure domaine `rotation_plan(...) -> Skip|Archive{keep_from=up_to}`.
|
||||
- Mécanique : verrou conversation bref ; réécriture actif **atomique en dernier** (tmp+rename) ; aucun tour perdu (∪ actif+archives) ; pagination dédoublonne par TurnId (crash-safe).
|
||||
|
||||
## Lecture paginée (port ISP `ConversationArchive`, impl FsConversationLog)
|
||||
- `page(conversation, PageCursor{anchor,direction Forward|Backward}, limit)` → `TurnSlice{turns, has_more}`. limit clampé [1,200] défaut 50. Ordre chrono croissant. Archive-aware.
|
||||
- Use case `ReadConversationPage` → DTO humain `TurnPage{turns:[TurnView{id,at_ms,role,source,text COMPLET,text_len}], has_more, next_anchor}`. **Texte complet, non borné, non distillé** = surface HUMAINE.
|
||||
- `ConversationLog` (append/read/last) inchangé = vue segment actif (chemin chaud + dérivation).
|
||||
|
||||
## Frontière
|
||||
Lecture riche consommée UNIQUEMENT par la commande Tauri du viewer humain, jamais par compose_convention_file/handoff/agent. Rotation ne touche que le transcript brut, jamais le handoff/injection.
|
||||
|
||||
## Frontend
|
||||
LS6 = backend + commande Tauri `read_conversation_page`. Tout le React (viewer) = LS7.
|
||||
26
.ideai/memory/conversation-viewer-ls7-frontend.md
Normal file
26
.ideai/memory/conversation-viewer-ls7-frontend.md
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
name: conversation-viewer-ls7-frontend
|
||||
description: Contrat figé du viewer de transcript paginé (frontend pur, lecture seule, surface humaine).
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
# LS7 — Viewer fil-par-paire (front pur)
|
||||
|
||||
Dernier lot fonctionnel du programme persistance. UI humaine qui rejoue le transcript par paire, consomme la commande LS6 `read_conversation_page`. Lecture seule, zéro impact backend/agent.
|
||||
|
||||
## Gateway / adapter / mock (patron WorkStateGateway)
|
||||
- Port `ConversationGateway.readPage(projectId, conversationId, {anchor?, direction?, limit?}) -> TurnPage`. Ajouter `conversation` à `Gateways`.
|
||||
- Types domaine : `TurnView{id, atMs, role: prompt|response|toolActivity, source: {kind:human}|{kind:agent,agentId}, text COMPLET, textLen}`, `TurnPage{turns, hasMore, nextAnchor}`.
|
||||
- Adapter `TauriConversationGateway` → invoke("read_conversation_page",{projectId,conversationId,cursor:{anchor,direction},limit}) + `conversationNormalization.ts` (mapper source Human/Agent calqué sur workStateNormalization). Mock avec pagination réelle + `_setTurns` pour tests offline.
|
||||
- Frontière : composant → useGateways().conversation → adapter → invoke. Jamais d'invoke direct.
|
||||
|
||||
## Modèle d'affichage
|
||||
- Clé = conversationId. Entrée = drill-down depuis le Work panel (`ConversationWorkSummary.conversationId` déjà énuméré ; rendre les lignes cliquables via prop `onOpenConversation`). Pas de nouvel appel « liste conversations ».
|
||||
- Rejeu chrono croissant ; distinction sobre User↔Agent vs Agent↔Agent (parties déduites des sources, noms résolus depuis l'inventaire agents) ; toolActivity atténué/replié.
|
||||
- Pagination : ouverture backward/None = dernière page (bas du fil) ; scroll-up = backward ancré sur le tour le plus ANCIEN du buffer (préfixe, dédup par id, hasMore gate) ; refresh queue = forward ancré sur le plus récent (manuel ou sur domain events delegationReady/orchestratorRequestProcessed).
|
||||
|
||||
## Intégration
|
||||
- État local `viewerConversationId` dans ProjectsView ; swap main-area (rend ConversationViewer à la place de LayoutGrid, PAS un nouveau kind backend) ; bouton retour ; reset au changement de projet. viewerConversationId=null ⇒ UI actuelle inchangée (non-régression terminal).
|
||||
|
||||
## Frontière / backend
|
||||
Lecture seule (read_conversation_page LS6, hors chemin chaud), jamais injecté dans un contexte agent. **Aucune part backend** : juste vérifier la signature de la commande exposée et aligner l'adapter si écart.
|
||||
15
.ideai/memory/git-agent-push-access-gitea-ssh.md
Normal file
15
.ideai/memory/git-agent-push-access-gitea-ssh.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
name: git-agent-push-access-gitea-ssh
|
||||
description: memory note git-agent-push-access-gitea-ssh
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
**CORRECTION (2026-06-23) — annule et remplace la note précédente : l'agent Git N'A PLUS l'accès push. Il est de nouveau STRICTEMENT LOCAL, comme avant.**
|
||||
|
||||
- Git gère **100 % du dépôt local** : commits, branches, merges/rebases locaux. Rien d'autre.
|
||||
- **Aucune action sortante** : pas de `git push`, pas de PR distante, pas de publication de tags, pas de synchronisation remote. Ce périmètre n'est PAS dans ses responsabilités.
|
||||
- Toute synchro avec un remote (`origin` Gitea ou autre) reste **hors périmètre Git** et sous décision/validation explicite de l'utilisateur, exécutée hors agent Git.
|
||||
|
||||
Le contexte d'agent `git.md` reflète déjà ce retour au strictement-local (garde-fou « tu restes strictement local, pas de `git push` »).
|
||||
|
||||
Voir [[git-owns-commit-merge-decisions]] (Git tranche toute la topologie LOCALE du dépôt).
|
||||
22
.ideai/memory/handoff-ls5-summary-bound-and-llm-seam.md
Normal file
22
.ideai/memory/handoff-ls5-summary-bound-and-llm-seam.md
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
name: handoff-ls5-summary-bound-and-llm-seam
|
||||
description: Contrat figé de la borne de handoff (perf) et du seam résumeur LLM non activé.
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
# LS5 — Borne handoff + seam LLM
|
||||
|
||||
Ferme le must-have perf du programme persistance : un `summary_md` non borné gonflait le contexte injecté à chaque lancement.
|
||||
|
||||
## Borne summary_md (déterministe, en CARACTÈRES, pas tokens)
|
||||
- **Par tour** : `render_turn` tronque le texte aplati à `TURN_LINE_MAX_CHARS=240` (infra summarizer). Corrige le trou réel (un gros Response = ligne géante).
|
||||
- **Totale** : fn PURE domaine `bound_handoff_summary(Handoff, max)` + `HANDOFF_SUMMARY_MAX_CHARS=4096`. Stratégie de dépassement = **troncature distillée** (garde objectif + lignes les plus récentes, drop oldest, frontière de ligne). JAMAIS re-fold compactant, JAMAIS rejet (n'bloque jamais l'append du log). `up_to`/`objective` jamais modifiés. Idempotent.
|
||||
- **Appliquée à l'écriture** (`RecordTurn` après `fold`, avant `save` → borne universelle quel que soit le résumeur) **ET défensivement à l'injection** (`resolve_handoff` avant compose → protège les `handoff.md` legacy non bornés, sans migration).
|
||||
|
||||
## Seam LLM : TRANCHÉ = « prêt mais NON activé »
|
||||
- Pas de vrai LLM en LS5 : `fold` tourne sur le chemin chaud (par tour, dans la délégation) → un appel réseau là = régression perf interdite. Défaut runtime reste `HeuristicHandoffSummarizer`.
|
||||
- Durcissement réel = la borne totale appliquée **dans RecordTurn (hors résumeur)** ⇒ un futur `LlmHandoffSummarizer` ne peut pas exploser le budget contexte.
|
||||
- Contrat futur adapter LLM (documenté) : déclenchement **froid/hors chemin** (reprise/rotation/débounce, jamais par tour) ; timeout + **fallback heuristique** (trait sans `Result`) ; sélection par flag, défaut heuristique. Trait `HandoffSummarizer::fold` inchangé.
|
||||
|
||||
## Frontière
|
||||
Transcript = `log.jsonl` (jamais injecté). `summary_md` = dérivé distillé, désormais borné à l'écriture et à l'injection. Conforme « surface agent = borné/distillé ».
|
||||
@ -0,0 +1,14 @@
|
||||
---
|
||||
name: idea-program-surface-separation-and-livestate
|
||||
description: Cadrage du programme post-skills : ce qui existe vs reste, et la règle de frontière surface-agent/humaine.
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
État au cadrage (develop @ 827d477) :
|
||||
- **#2a handoff incrémental cross-profile = FAIT + CÂBLÉ** (lots P1–P8) : `domain/conversation_log.rs` (`Handoff`, `HandoffStore`, `HandoffSummarizer::fold` incrémental, `ProviderSessionStore`), `application/conversation/record.rs` (`RecordTurn` = append+fold), wiring `state.rs` (`AppRecordTurnProvider`), injection au lancement via `HandoffProvider` (P7). Résumeur = `HeuristicHandoffSummarizer`, seam async pour `LlmHandoffSummarizer` (P10) déjà en place. Reste : seam LLM + borne `summary_md`.
|
||||
- **#2b log canonique = FAIT** : `ConversationLog` append-only `.ideai/conversations/<id>/log.jsonl`, **jamais injecté à un agent** (doc domaine explicite). Reste : rétention/rotation + lecture paginée UI.
|
||||
- **#1 live-state agent = À CONSTRUIRE (cœur)** : aujourd'hui seul `GetProjectWorkState` (read-model HUMAIN dérivé, non durable). Construire un 4ᵉ store `live-state.json` (**gitignored, runtime**) : `domain/live_state.rs` (`LiveState`/`LiveEntry`/`WorkStatus`, port `LiveStateStore`, **keyed last-writer-wins, JAMAIS append**, champs bornés, `prune` TTL+max_n), use cases `UpdateLiveState`/`GetLiveStateLean`, adapter `FsLiveStateStore`, auto-update depuis `orchestrator/service.rs` (ask→Working, reply→Done), injection bornée `# État du projet` au lancement + outils MCP `idea_workstate_read`/`idea_workstate_set`. Ne stocke QUE le non-re-dérivable (intent/progrès/dernière délégation) ; busy/queue restent calculés.
|
||||
|
||||
**Règle de frontière gravée (testable)** : Surface AGENT = borné/distillé/pointeur uniquement (capacités, pointeurs mémoire, affordances skills, handoff `summary_md`, live-state lean). Surface HUMAINE = riche (ProjectWorkStatePanel, viewer fil-par-paire qui rejoue le log). **Transcript / append-only INTERDIT d'injection dans un contexte agent** ; seul un dérivé distillé franchit. 4 stores distincts : `memory/` (savoir stable, versionné) · `handoff.md` (reprise par fil) · `log.jsonl` (transcript humain) · `live-state.json` (coordination transitoire maigre).
|
||||
|
||||
Découpage : LS0 doc baseline → LS1 domaine live-state → LS2 store+usecases → LS3 auto-update délégation → LS4 injection+MCP (clôt cold-start) ; LS5 seam LLM+borne handoff, LS6 rétention log+lecture UI (parallèles) ; LS7 UX fil-par-paire (front pur) ; LS8 doc clôture.
|
||||
15
.ideai/memory/live-state-persistence-program-closed-ls8.md
Normal file
15
.ideai/memory/live-state-persistence-program-closed-ls8.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
name: live-state-persistence-program-closed-ls8
|
||||
description: Le programme live-state + persistance conversationnelle est livré et documenté ; pointe la doc de clôture et les points restés ouverts.
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
Programme **live-state / persistance conversationnelle CLOS** (LS1→LS7 livrés @ fd7adbb ; LS8 = doc de clôture).
|
||||
|
||||
**Doc de référence** : `docs/LS8-live-state-persistence-closure.md` + `ARCHITECTURE.md` §21 (cartographie des 4 stores) ; §19 retitré « LIVRÉ » ; §14.1 et §18.5 corrigés (catalogue MCP **14**).
|
||||
|
||||
**4 stores disjoints** : `.ideai/memory/` (savoir stable, versionné) · `handoff.md` (reprise distillée bornée ≤4096) · `log.jsonl` (transcript humain riche, JAMAIS injecté) · `live-state.json` (coordination maigre runtime, gitignoré). Surface AGENT bornée/distillée/pointeur ; surface HUMAINE riche ; seul le handoff distillé franchit vers un contexte agent.
|
||||
|
||||
**Restant ouvert** : (1) activation seam LLM `LlmHandoffSummarizer` (non activé, défaut heuristique, contrat ADR LS5) ; (2) sweep périodique de rotation (idempotent, non câblé) ; (3) **discordance D19-4 ↔ .gitignore** : `.ideai/conversations/` devait être gitignoré mais est suivi — à trancher Git/Main ; (4) intégration MCP e2e UX ; (5) multi-fenêtres registre sessions ; (6) auto-update mémoire/contexte en cours de session.
|
||||
|
||||
**Contrainte d'écriture** : un agent lancé en run-dir isolé (`.ideai/run/<id>/`) **ne peut pas écrire l'arbre du project root** (ARCHITECTURE.md, docs/) — les modifs de doc passent par Git (write+commit authority).
|
||||
21
.ideai/memory/live-state-reboot-reconciliation-design.md
Normal file
21
.ideai/memory/live-state-reboot-reconciliation-design.md
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
name: live-state-reboot-reconciliation-design
|
||||
description: memory note live-state-reboot-reconciliation-design
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
title: Réconciliation du live-state au reboot (ReconcileLiveState)
|
||||
type: reference
|
||||
description: Décision d'architecture pour réconcilier les lignes live-state fantômes au redémarrage — seam, source de vérité, contrat de statut et préservation du self-only.
|
||||
---
|
||||
**Problème** : au reboot, `.ideai/live-state.json` n'est pas réconcilié → agents fantômes `working/waiting/blocked` alors que leurs sessions sont mortes. `prune` (TTL 6h) ne couvre pas le fantôme récent.
|
||||
|
||||
**Décision (cadrage Architect, 2026-06-23)** :
|
||||
- **Seam** : étape best-effort `reconcile_live_state` dans la chaîne `open_project` (commands.rs), juste après `reconcile_layouts`. Pas d'app-boot global (live-state est par-projet). Pas d'outil MCP. Justification : un crash ne déclenche jamais `close_project`, donc **open est le seul filet fiable**.
|
||||
- **Source de vérité** : le registre de sessions vivantes `LiveSessions` / trait `LiveAgentRegistry` (`application/src/terminal/registry.rs`) — la *même* vérité que `GetProjectWorkState`. Prédicat orphelin = `status ∈ {working,waiting,blocked}` ET `!is_agent_live`. Race-safe : tourne avant toute relance ; LWW gagne via `updated_at_ms` frais.
|
||||
- **Contrat** : orphelin → `idle` (pas de nouveau statut, évite le ripple DTO/front). Garder `intent` (trace), vider `ticket` + `last_delegation` (rendez-vous mort, tracé ailleurs dans log/handoff), `progress` = marqueur stale, `updated_at_ms` frais.
|
||||
- **Pas de nouveau port.** Use case applicative `ReconcileLiveState` (compose `LiveStateStore` + `LiveAgentRegistry` + `Clock`) + transformation **pure** `LiveState::reconcile_orphans(is_live, now)` dans `domain/src/live_state.rs`. Provider par-root côté app-tauri (calqué sur `LiveStateProvider`/`live_state_for`).
|
||||
- **Self-only de `idea_workstate_set`** : invariant **de la surface MCP**, pas du store. `set_workstate` lie `agent_id`=identité handshake ; `UpdateLiveState`/`LiveStateStore` sont identity-agnostic. La réconciliation est un **acte système** dans le composition root qui appelle le port directement, **jamais** via `OrchestratorCommand::SetWorkState` → self-only préservé par construction. Même split que `snapshot_running_agents`/`reconcile_layouts`.
|
||||
|
||||
Fichiers probables : `domain/src/live_state.rs`, `application/src/workstate/{mod.rs,reconcile.rs}`, `app-tauri/src/{lib.rs,state.rs,commands.rs}`. Voir [[live-state-persistence-program-closed-ls8]], [[handoff-ls5-summary-bound-and-llm-seam]].
|
||||
47
.ideai/memory/mcp-e2e-findings-reply-wedge-phantom-busy.md
Normal file
47
.ideai/memory/mcp-e2e-findings-reply-wedge-phantom-busy.md
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
name: mcp-e2e-findings-reply-wedge-phantom-busy
|
||||
description: memory note mcp-e2e-findings-reply-wedge-phantom-busy
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
name: mcp-e2e-findings-reply-wedge-phantom-busy
|
||||
description: Findings validation MCP e2e live (AppImage 0.3.0) — transport/rendez-vous SAINS ; un seul vrai défaut = wedge si l'agent délégué n'appelle pas idea_reply (pas de timeout serveur).
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# Findings validation MCP e2e (live, AppImage 0.3.0) — 2026-06-22
|
||||
|
||||
Contexte : validation réelle du parcours inter-agents (cf. [[resume-after-appimage-rebuild-mcp-e2e]]). Méthode = Main observe en externe (Bash sur `ss -xp` + transcripts `~/.claude/projects/<run-dir-encodé>/*.jsonl`), l'utilisateur déclenche dans l'UI ; on ne valide PAS via `idea_ask_agent`.
|
||||
|
||||
## Scénario 1 — délégation vers agent FROID + cycle complet : VERDICT
|
||||
- ✅ **Réveil à froid** : déléguer vers un agent arrêté relance son pont (`mcp-server --requester <id>` réapparaît, socket ESTAB recompte).
|
||||
- ✅ **1er tour non perdu** : tâche livrée intacte = 1er `user` `[IdeA · tâche de <agent> · ticket <uuid>] …`.
|
||||
- ✅ **Chemin positif `idea_reply`** : quand l'agent cible appelle `idea_reply(ticket,result)`, le bridge répond `reply ... delivered`, le **demandeur reçoit le `tool_result` et reprend la main** (vérifié : DevBackend reçoit `pong` puis continue).
|
||||
- ✅ **Purge live-state** : dès l'`idea_reply`, `idea_workstate` repasse le cible de `working` → `done`, intent vidé.
|
||||
|
||||
➡️ **Transport + protocole de rendez-vous = SAINS.** Bugs historiques 3/4/5 OK sur ce chemin.
|
||||
|
||||
## LE défaut restant (racine unique) — wedge sans `idea_reply`
|
||||
Si l'agent délégué **termine son tour sans appeler `idea_reply`** (ex. tâche triviale « réponds pong » → il répond `pong` en **prose** et s'arrête) :
|
||||
- le **demandeur wedge indéfiniment** dans `idea_ask_agent` (transcript demandeur figé sur le `tool_use` idea_ask_agent, aucun `tool_result`) ;
|
||||
- la **cible reste `working`** sur le ticket périmé dans la live-state ;
|
||||
- **aucun timeout ni récupération** côté serveur. Une interruption utilisateur du `ask` libère le demandeur mais **ne purge pas** le `working` de la cible (purge seulement à l'`idea_reply`).
|
||||
|
||||
➡️ Le « Busy fantôme » n'est PAS un bug d'état indépendant : c'est la **conséquence** de l'absence d'`idea_reply`. Une seule cause à traiter.
|
||||
|
||||
### Pistes correctif (à arbitrer Architect)
|
||||
1. **Durcir contextes agents** : « toute tâche déléguée se termine IMPÉRATIVEMENT par `idea_reply`, même triviale » (cheap, attaque la cause comportementale).
|
||||
2. **Garde-fou serveur (rendez-vous)** : timeout sur l'attente `idea_ask_agent` → renvoyer au demandeur un résultat d'échec/relance explicite + purger le `working` de la cible (idempotent). Touche le contrat rendez-vous + cycle de vie live-state = domaine Architect. Voir [[idea-program-surface-separation-and-livestate]], [[mcp-bridge-and-delegation-runtime-notes]].
|
||||
|
||||
## Diagnostic / repro (rappels)
|
||||
- Ponts : `pgrep -af 'mcp-server --endpoint'` (1 requester = 2 process) ; `ss -xp | grep -c idea-mcp`.
|
||||
- Reply réel = `tool_use` `idea_reply` dans le transcript cible → tool_result `reply ... delivered` (⚠️ ne pas confondre avec les mentions `idea_reply` du CLAUDE.md injecté via attachments).
|
||||
- Wedge demandeur = transcript demandeur s'arrête sur `tool_use` `idea_ask_agent` sans `tool_result`.
|
||||
- ⚠️ Horodatages transcripts = **UTC** ; `ls %H:%M:%S` masque la date → comparer avec `date` + mtime réel (`ls -t`).
|
||||
|
||||
## Restant à tester (scénarios e2e suivants)
|
||||
- Délégation vers agent BACKGROUND (node_id None) — même protocole, vérifier pas de 1er tour perdu.
|
||||
- `ask` sans réponse ne wedge pas durablement la CONNEXION du demandeur (vs juste l'appel) — Bug 5 côté transport.
|
||||
- Profils Claude/Codex utilisent MCP par défaut ; fallback fichier+prose cohérent.
|
||||
- Observabilité UI des délégations/replies (aujourd'hui opaque) — sujet UX.
|
||||
45
.ideai/memory/mcp-functional-test-plan-2026-06-24.md
Normal file
45
.ideai/memory/mcp-functional-test-plan-2026-06-24.md
Normal file
@ -0,0 +1,45 @@
|
||||
---
|
||||
name: mcp-functional-test-plan-2026-06-24
|
||||
description: memory note mcp-functional-test-plan-2026-06-24
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
name: mcp-functional-test-plan-2026-06-24
|
||||
description: Plan de test FONCTIONNEL du rendez-vous inter-agents MCP (trivial→tordu), à exécuter après rebuild develop HEAD ; méthode, ordre, setup IdeA et critères de réussite.
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# Plan de test fonctionnel MCP inter-agents (2026-06-24, run a6ced819)
|
||||
|
||||
Objectif : état des lieux par tests **fonctionnels** (pas unitaires) du rendez-vous `idea_ask_agent` ⇄ `idea_reply`, du trivial au plus tordu. On lance dans l'ordre, on **s'arrête au 1er blocage**, on corrige (cycle Architect→Git→Dev→QA), rebuild+relance, puis on **reprend de T1**. Contexte/historique : [[mcp-e2e-findings-reply-wedge-phantom-busy]], [[backstop-fires-on-intra-task-turn-rootcause]], [[rendezvous-no-reply-backstop-design]], [[rendezvous-600s-cap-too-short-heavy-tasks]], [[reconcile-live-state-implemented-feature-branch]].
|
||||
|
||||
## Contexte binaire au moment du plan
|
||||
- AppImage qui tournait = build **23/06 19:42**, PÉRIMÉ (antérieur à `c6f0f86` encode_cwd, `744de20` backstop no-reply, `886bb0d`/`1efe2f1` reconcile). Décision utilisateur : **rebuild develop HEAD `1efe2f1` puis relance** avant de tester.
|
||||
- Règle structurelle : **binaire qui tourne = AppImage**. Tout fix backend ⇒ rebuild + relance d'IdeA (tue Main). Les tests s'enchaînent SANS relance *à l'intérieur d'une même version* ; chaque cycle de fix = 1 relance.
|
||||
|
||||
## Méthode
|
||||
- **Main est le demandeur** (`idea_ask_agent`) = test fidèle de « si je donne un message à un agent, il me répond ».
|
||||
- Doublé d'**observation externe Bash** : ponts `ss -xp | grep idea-mcp` et `pgrep -af mcp-server` ; transcripts `~/.claude/projects/<run-dir-encodé>/*.jsonl` (horodatages **UTC** ; reply réel = `tool_use` idea_reply→tool_result `reply … delivered` ; wedge demandeur = transcript figé sur `tool_use` idea_ask_agent sans tool_result) ; live-state via `idea_workstate_read`.
|
||||
- Risque résiduel : un wedge non borné fige le tour de Main → l'utilisateur peut interrompre.
|
||||
|
||||
## Setup IdeA à mettre en place avant T1 (consigne utilisateur)
|
||||
1. Relancer IdeA, ouvrir le projet IdeA, **Main visible** (le demandeur).
|
||||
2. Garder **2–3 cellules libres visibles** pour qu'on observe à l'œil les délégations (Main y placera des cibles visibles, ou lance-toi QA + DevFrontend dans des cellules visibles).
|
||||
3. **Laisser Architect, DevBackend, Git ARRÊTÉS (froids)** : T3 testera le réveil à froid ; T9 utilisera Architect+DevBackend froids.
|
||||
4. Cibles chaudes pour T1/T2 : Main les réchauffe lui-même (launch) — pas d'action requise.
|
||||
|
||||
## Ordre des tests (trivial → tordu)
|
||||
- **T1 — Visibilité outils MCP.** Un agent lancé par IdeA voit ses outils sans action manuelle. Vérif : pont ESTAB (`ss`) + 2 process mcp-server par requester.
|
||||
- **T2 — Cible CHAUDE + idea_reply trivial.** Main→ask(agent chaud, « réponds pong via idea_reply »). Attendu : réponse inline `pong`, temps borné, workstate working→done purgé.
|
||||
- **T3 — Réveil à FROID + idea_reply.** Cible arrêtée. Attendu : pont relancé (nouveau mcp-server), **1er tour non perdu** (1er user `[IdeA · tâche…]` intact), reply remonte.
|
||||
- **T4 — Cible BACKGROUND (node_id None).** Délégation vers agent sans cellule visible. Attendu : même protocole, pas de 1er tour perdu (historiquement non testé).
|
||||
- **T5 — NO-REPLY (cible répond en prose, pas d'idea_reply).** Attendu backstop : demandeur libéré en temps borné avec `TargetReturnedNoReply` (retryable), **pas de Busy fantôme** (workstate purgé). DÉFAUT historique #1.
|
||||
- **T6 — Délégation MULTI-ÉTAPES puis idea_reply.** Cible lit plusieurs fichiers / lance une cmd PUIS idea_reply. Attendu : **pas de libération prématurée** pendant le travail, rapport final livré. PIÈGE turn-watcher (cause racine : backstop tirait au 1er tour interne ~3 s).
|
||||
- **T7 — Tâche LOURDE > plafond** (impl + `cargo test`/clippy). Attendu : extension sur signe de vie OU message clair « cible active, plafond atteint » (≠ faux `-32001`) ; idea_reply tardif non perdu. Plafond `IDEA_ASK_RENDEZVOUS_TIMEOUT_MS` (défaut 600000).
|
||||
- **T8 — Délégations PARALLÈLES** (2 cibles en 1 tour Main). Attendu : rendez-vous multiples simultanés OK, multiplexage pont, 2 réponses distinctes.
|
||||
- **T9 — TRANSITIVE A→B→C** (Main→Architect, Architect délègue à DevBackend puis reply à Main). Attendu : rendez-vous imbriqués, 2 attentes simultanées sans deadlock. Cas le plus tordu.
|
||||
- **T10 — INTERRUPTION/annulation + reconcile reboot.** (a) Main interrompt un ask en vol → `working` cible purgé, pas de cascade, idea_reply tardif non-livrable proprement. (b) Au reboot, orphelins status∈{working,waiting,blocked} & session morte → `idle` + marker `STALE_AT_RESTART_MARKER` (use case ReconcileLiveState, cf. [[reconcile-live-state-implemented-feature-branch]]).
|
||||
|
||||
## Critère de fin
|
||||
Tous les T1→T10 verts avec preuve réelle (réponse inline + observation externe cohérente). Sinon : 1er rouge = blocage à corriger, puis reprise de T1.
|
||||
@ -0,0 +1,33 @@
|
||||
---
|
||||
name: mcp-functional-tests-t1-t9-green-live-2026-06-24
|
||||
description: memory note mcp-functional-tests-t1-t9-green-live-2026-06-24
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
title: MCP tests fonctionnels T1→T9 VERTS en live (2026-06-24, AppImage 12:53 HEAD 1efe2f1 + fix T7 non committé)
|
||||
type: project
|
||||
description: Passe complète T1→T9 verte en conditions réelles sur AppImage du 24/06 12:53 ; T5 (backstop no-reply) et T7 (watchdog inactivité >600s) validés live ; reste T10 (interruption + reconcile reboot) qui exige action utilisateur.
|
||||
---
|
||||
# Tests fonctionnels MCP rendez-vous — T1→T9 VERTS live (2026-06-24)
|
||||
|
||||
Run a6ced819, plan [[mcp-functional-test-plan-2026-06-24]]. AppImage **rebuild 12:53 depuis l'arbre de travail** (HEAD `1efe2f1` + le fix T7 watchdog **non committé** mais présent dans les 11 fichiers modifiés du git status → embarqué dans le binaire). Méthode : Main demandeur + observation externe (ss/pgrep/transcripts UTC/workstate).
|
||||
|
||||
## Résultats (preuve réelle)
|
||||
- **T1 visibilité MCP** ✅ : agents chauds = pont ESTAB + 2 mcp-server (app-tauri parent + AppImage) chacun.
|
||||
- **T2 cible chaude + reply trivial** ✅ : DevFrontend → `pong` inline, reply delivered 10:56:51 UTC, workstate done (pas de Busy fantôme).
|
||||
- **T3 réveil à FROID** ✅ : Git froid → `pong-cold` ; nouveau pont spawné, **1er tour `[IdeA·tâche]` intact** (régresseur encode_cwd résolu), reply delivered 10:57:34.
|
||||
- **T4 cible BACKGROUND (node_id None)** ✅ : Git background → `pong-bg`, reply delivered 10:58:14.
|
||||
- **T5 NO-REPLY backstop** ✅ (défaut historique #1 résolu) : cible répond en prose sans idea_reply → demandeur libéré en ~20 s avec erreur retryable « returned to its prompt without calling idea_reply », workstate cible done (PAS de Busy fantôme).
|
||||
- **T6 multi-étapes** ✅ (piège turn-watcher résolu) : DevFrontend lit fichiers + git log PUIS idea_reply ; pas de libération prématurée ; données réelles (142 fichiers, hashes corrects).
|
||||
- **T7 tâche LOURDE >600s** ✅ (défaut historique #2 résolu, validation live du fix watchdog) : QA charge réelle continue 11:00:46→11:12:44 UTC = **~11m58s**, cargo clean+build release+test (1632 passed/0)+clippy+9 relances ; rendez-vous **NON expiré à 600s**, idea_reply accepté au-delà du plafond (aucun « no pending request »), reply delivered 11:13:21.
|
||||
- **T8 PARALLÈLE** ✅ : 2 asks même tour (DevFrontend `alpha-8` + Git `beta-8`), réponses distinctes, multiplexage pont OK.
|
||||
- **T9 TRANSITIF A→B→C** ✅ : Main→Architect→DevBackend (les 2 froids) → `relay:gamma-9:done` ; rendez-vous imbriqués + double réveil à froid sans deadlock ; DevBackend reply delivered 11:14:32.
|
||||
|
||||
## Reste : T10 (exige action utilisateur)
|
||||
- **T10a interruption** : Main interrompt un ask en vol → attendu : workstate cible purgé, pas de cascade, idea_reply tardif proprement non-livrable. NÉCESSITE que l'utilisateur appuie sur interrupt pendant un ask wedgé.
|
||||
- **T10b reconcile reboot** : orphelin status∈{working,waiting,blocked} + session morte → au reboot, use case ReconcileLiveState le passe à idle + `STALE_AT_RESTART_MARKER` (cf. [[reconcile-live-state-implemented-feature-branch]]). NÉCESSITE un reboot d'IdeA (ferme Main).
|
||||
|
||||
## Suite recommandée
|
||||
1. Faire committer le fix T7 par Git (encore non committé, cf. [[git-owns-commit-merge-decisions]] + [[rendezvous-600s-cap-too-short-heavy-tasks]]).
|
||||
2. Exécuter T10 avec l'utilisateur (interrupt + reboot).
|
||||
@ -0,0 +1,29 @@
|
||||
---
|
||||
name: mcp-t10a-harness-interrupt-does-not-cancel-rendezvous
|
||||
description: memory note mcp-t10a-harness-interrupt-does-not-cancel-rendezvous
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
title: T10a — l'interrupt harness du demandeur n'annule PAS le rendez-vous backend (reply tardif accepté dans le vide)
|
||||
type: reference
|
||||
description: Finding T10a (2026-06-24) — interrompre Main (demandeur) au niveau Claude Code ne propage aucune annulation à IdeA ; la cible finit, son idea_reply est « delivered » dans un demandeur abandonné, et la live-state du demandeur reste working.
|
||||
---
|
||||
# Finding T10a (2026-06-24, run a6ced819)
|
||||
|
||||
## Setup
|
||||
Main → `idea_ask_agent(DevFrontend, "travaille ~90s puis idea_reply late-10a")`. Pendant l'attente, l'utilisateur **interrompt Main** (Échap harness Claude Code). Le tool use `idea_ask_agent` est rejeté côté harness.
|
||||
|
||||
## Observé
|
||||
- DevFrontend a fini ses ~95 s de travail réel (11:20:39→11:22:14 UTC) puis `idea_reply("late-10a")` → **ACCEPTÉ « delivered »** à 11:22:18 (PAS « no pending request »).
|
||||
- DevFrontend workstate = **done** (pas d'orphelin côté cible). Pas de cascade.
|
||||
- **Main (demandeur) workstate resté `working`** : l'interrupt a coupé le tour de Main avant son nettoyage ; le chemin interrupt ne réconcilie pas la live-state du demandeur.
|
||||
|
||||
## Interprétation
|
||||
L'interrupt Claude Code annule le **tool call local** mais le **process Main survit** → la socket MCP (mcp-server du demandeur) reste connectée → IdeA ne reçoit aucun signal d'annulation → le rendez-vous reste pending → le reply tardif de la cible est livré dans un demandeur qui a déjà abandonné (perdu pour Main mais rapporté « delivered »).
|
||||
|
||||
## Conséquence
|
||||
- Le T10a du plan (« annulation en vol → reply tardif non-livrable proprement ») **n'est pas exerçable via interrupt harness** tant que le process demandeur survit. Une vraie annulation exigerait : tuer le process demandeur (drop socket) OU un cancel protocolaire JSON-RPC.
|
||||
- Comportement néanmoins bénin : pas de wedge, pas de cascade, cible réconciliée (done). Seuls écarts : (a) reply tardif « delivered » au lieu de rejeté ; (b) live-state du demandeur laissée working par le chemin interrupt (mais reconcile-au-reboot la rattraperait, cf. [[reconcile-live-state-implemented-feature-branch]]).
|
||||
|
||||
Lié à [[mcp-functional-tests-t1-t9-green-live-2026-06-24]], [[mcp-functional-test-plan-2026-06-24]].
|
||||
24
.ideai/memory/mcp-t10b-pending-reboot-verification.md
Normal file
24
.ideai/memory/mcp-t10b-pending-reboot-verification.md
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
name: mcp-t10b-pending-reboot-verification
|
||||
description: memory note mcp-t10b-pending-reboot-verification
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
title: T10b PASS — reconcile au reboot vérifié, inclut l'orchestrateur (2026-06-24)
|
||||
type: project
|
||||
description: T10b validé live après reboot. ReconcileLiveState ramène l'orphelin Main working→idle en conservant l'intent et purgeant ticket/lastDelegation. Couvre l'orchestrateur. Reste : faire committer par Git les fix non committés (T7 watchdog + reconcile).
|
||||
---
|
||||
# T10b — PASS (reboot reconcile vérifié)
|
||||
|
||||
## Verdict
|
||||
Orphelin armé = Main `working` intent "T10b-ORPHAN-MAIN". Après reboot (run a6ced819), `idea_workstate_read` montre Main :
|
||||
- `status: idle` ✅ (était working)
|
||||
- `intent` conservé ✅
|
||||
- `ticket` purgé ✅ / `lastDelegation` purgé ✅
|
||||
|
||||
Signature `STALE_AT_RESTART_MARKER` complète. **ReconcileLiveState valide ET inclut l'orchestrateur** (Main n'a PAS été exclu malgré la crainte du design open_project). Champ `progress` non exposé par workstate_read mais transition working→idle+intent retenu = concluante.
|
||||
|
||||
## Suite du plan
|
||||
T1→T10 du plan [[mcp-functional-test-plan-2026-06-24]] terminés (T1→T9 verts cf. [[mcp-functional-tests-t1-t9-green-live-2026-06-24]], T10a finding [[mcp-t10a-harness-interrupt-does-not-cancel-rendezvous]], T10b PASS ici).
|
||||
**RESTE : faire committer par Git les fix non committés (T7 backstop/watchdog + reconcile live-state).** cf. [[git-owns-commit-merge-decisions]].
|
||||
@ -0,0 +1,37 @@
|
||||
---
|
||||
name: mcp-t7-backstop-600s-reply-rejected-livestate-stale
|
||||
description: memory note mcp-t7-backstop-600s-reply-rejected-livestate-stale
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
title: MCP T7b/T7e — backstop 600s rejette le reply tardif et laisse le live-state worker non réconcilié
|
||||
type: reference
|
||||
description: Finding fonctionnel des tests MCP T7b/T7e (2026-06-24) — un idea_reply après dépassement de la fenêtre 600s est refusé « no pending request », et le ticket du worker reste working dans le live-state.
|
||||
---
|
||||
|
||||
# Finding — tests MCP T7 (2026-06-24, QA)
|
||||
|
||||
## Contexte
|
||||
Série de tests du rendez-vous `idea_ask_agent ⇄ idea_reply` et du backstop no-reply (cap ~600s), demandés par Main :
|
||||
- **T7d** (debug build x3, avant-plan) : cumul ~3m49s < 600s → reply OK.
|
||||
- **T7b** (9 étapes `sleep 82`, entrelacées) : le harness BLOQUE tout `sleep` avant-plan → exécutées en run_in_background ; reply OK (tardif mais < fenêtre côté ticket T7b).
|
||||
- **T7e** (release build répété, avant-plan, sans sleep ni bg) : 7 cycles, cumul réel **08:01:14 → 08:14:21 = 13 min 07 s**, franchit largement 600s.
|
||||
|
||||
## Défaut observé
|
||||
À la fin de T7e (et de T7b, terminé au même tour, après >600s d'occupation continue), les DEUX `idea_reply` (tickets `4613262f…` T7b et `d2398b22…` T7e) sont refusés :
|
||||
|
||||
```
|
||||
invalid input: no pending request to reply to for agent aefdbd61-…
|
||||
```
|
||||
|
||||
→ Le backstop a libéré le **demandeur** (Main) côté rendez-vous après dépassement du cap, ce qui est le comportement voulu. MAIS :
|
||||
1. Le **résultat réel** (builds OK, horodatages non falsifiés) ne peut **plus être délivré** : il est perdu pour le demandeur.
|
||||
2. `idea_workstate_read` montre encore le worker QA `status=working ticket=d2398b22…` **après** le rejet du reply → le live-state du **worker** n'est PAS réconcilié quand le backstop ferme le rendez-vous côté demandeur. Incohérence demandeur (libéré) vs worker (toujours working).
|
||||
|
||||
## Conséquence / piste
|
||||
- Le cap 600s du rendez-vous reste trop court pour des tâches lourdes légitimes (cf. [[rendezvous-600s-cap-too-short-heavy-tasks]]) : ici un travail réel et honnête >13 min est « jeté ».
|
||||
- À corriger : quand le backstop ferme un rendez-vous, soit (a) accepter encore un reply tardif (le router vers le demandeur même après timeout / le persister), soit (b) réconcilier le live-state du worker (passer son ticket à done/abandon) pour ne pas laisser un `working` fantôme. Voir [[backstop-fires-on-intra-task-turn-rootcause]] et [[rendezvous-no-reply-backstop-design]].
|
||||
|
||||
## Reproductible
|
||||
Charge avant-plan réelle (`cargo build --release --workspace` en boucle clean) dépassant 600s, puis tenter `idea_reply` sur le ticket d'origine → rejet systématique.
|
||||
@ -0,0 +1,25 @@
|
||||
---
|
||||
name: reconcile-live-state-implemented-feature-branch
|
||||
description: memory note reconcile-live-state-implemented-feature-branch
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
title: Réconciliation du live-state au reboot — implémentée (feature/reconcile-live-state)
|
||||
type: project
|
||||
description: Le chantier ReconcileLiveState (3 lots) est implémenté et vert (1623 tests), non committé ; détail des fichiers et de l'arbitrage project_id/provider.
|
||||
---
|
||||
|
||||
Implémenté le 2026-06-23 sur `feature/reconcile-live-state` (ticket Main a7fcb5e4, dont le rendez-vous `idea_reply` a expiré pendant le build — résultat consigné ici). **Non committé** (Git tranche). Cadrage : [[live-state-reboot-reconciliation-design]].
|
||||
|
||||
**Résultats réels** : `cargo test --workspace` = **1623 passed, 0 failed**. `cargo clippy --workspace --all-targets` = 0 erreur, aucun warning sur le code ajouté (warnings restants tous pré-existants).
|
||||
|
||||
**Lot 1 (domaine, `crates/domain/src/live_state.rs`)** : `LiveState::reconcile_orphans(is_live, now_ms) -> Vec<LiveEntry>` pure (ne mute pas self). Orphelin = status ∈ {Working,Waiting,Blocked} ET !is_live → réécrit status=Idle, intent gardé, ticket=None, last_delegation=None, progress=Some(`STALE_AT_RESTART_MARKER`), updated_at_ms=now. Const pub `STALE_AT_RESTART_MARKER = "(stale — session not running at restart)"`. +4 tests.
|
||||
|
||||
**Lot 2 (application, nouveau `crates/application/src/workstate/reconcile.rs`)** : use case `ReconcileLiveState` sur `LiveStateStore`+`LiveAgentRegistry`(ISP)+`Clock` ; `execute(ReconcileLiveStateInput{project_id})` charge → reconcile_orphans → upsert par ligne. +3 tests. Exporté via workstate/mod.rs + application/lib.rs.
|
||||
|
||||
**Lot 3 (app-tauri, `state.rs`+`commands.rs`)** : provider par-root `AppReconcileLiveState` (résout root via `ProjectStore::load_project`, `FsLiveStateStore::new(&root)`, registre = `LiveSessions` existant). Champ `reconcile_live_state` sur AppState. Hook best-effort dans `open_project` après `reconcile_layouts`. **Acte système** : écrit le port `LiveStateStore` directement, jamais via `OrchestratorCommand::SetWorkState` → self-only de `idea_workstate_set` préservé par construction.
|
||||
|
||||
**Arbitrage à valider QA/Architect** : la résolution project_id→root se fait au composition root (le store est root-bound), donc `ReconcileLiveState::execute` reçoit bien `ReconcileLiveStateInput{project_id}` (conforme Lot 2 + hook Lot 3 à la lettre) mais ne relit pas project_id dans le flux pur (`_input`). Variante sans ce param redondant = ajustement trivial si souhaité.
|
||||
|
||||
**Fichiers (6)** : domain/src/live_state.rs ; application/src/workstate/reconcile.rs (nouveau) ; application/src/workstate/mod.rs ; application/src/lib.rs ; app-tauri/src/state.rs ; app-tauri/src/commands.rs.
|
||||
37
.ideai/memory/rendezvous-600s-cap-too-short-heavy-tasks.md
Normal file
37
.ideai/memory/rendezvous-600s-cap-too-short-heavy-tasks.md
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
name: rendezvous-600s-cap-too-short-heavy-tasks
|
||||
description: memory note rendezvous-600s-cap-too-short-heavy-tasks
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
name: rendezvous-600s-cap-too-short-heavy-tasks
|
||||
description: FIX LIVRÉ (2026-06-24) du plafond rendez-vous 600s trop court (T7) — watchdog d'inactivité + extension sur signe de vie + plafond absolu, message distinct cible-active vs no-reply. Built, tests verts, AppImage 09:21 ; validation live T7 en attente.
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# T7 — plafond rendez-vous trop court : FIX LIVRÉ (2026-06-24)
|
||||
|
||||
## Défaut (rappel, observé 2026-06-23)
|
||||
Délégation dev lourde (impl + `cargo test --workspace` + clippy) → la cible bosse en **un seul long tour > 600 s sans émettre de `turn_duration`**. L'enveloppe serveur `timeout(600s, dispatch)` plate (`crates/infrastructure/src/orchestrator/mcp/server.rs`) expirait sec : (a) faux `-32001`/no-reply **retryable** alors que la cible n'est pas muette mais active ; (b) drop du `dispatch` → canal de report mort → `idea_reply` final non livrable (« no pending request »).
|
||||
|
||||
## Fix (branche de travail courante, pas encore committé)
|
||||
Implémenté par subagent Claude (Architect+DevBackend, hors `idea_ask_agent` car le rendez-vous était le sujet), vérifié par Main (QA réelle), AppImage rebuildée.
|
||||
- **Algorithme `run_inactivity_watchdog`** dans `server.rs` : `ASK_RENDEZVOUS_TIMEOUT` (600 s, env `IDEA_ASK_RENDEZVOUS_TIMEOUT_MS`) devient une **fenêtre d'inactivité (budget de silence)**, pas un plafond absolu. Boucle `timeout(fenêtre, dispatch)` ; à chaque expiration, sonde l'activité de la cible :
|
||||
- progrès & sous plafond → réarme (extension) ;
|
||||
- progrès & plafond atteint → **`rendezvous_ceiling_active_error`** (nouveau code JSON-RPC `error_codes::RENDEZVOUS_CEILING_ACTIVE = -32_002`, `data.code="RENDEZVOUS_CEILING_ACTIVE"`, **`retryable:false`**, message « still actively working… do not retry blindly, check the target's in-progress work/branch ») ;
|
||||
- pas de progrès (vrai silence, ou **pas de probe = fallback plat**) → `rendezvous_no_reply_error` inchangé (`retryable:true`).
|
||||
- **Signe de vie = octets cumulés des `.jsonl`** du run-dir cible (couvre le long tour unique sans `turn_duration`). Nouvelle `inspector::claude_paths::transcript_activity_token(fs, home, cwd) -> Option<u64>`.
|
||||
- **Plafond absolu** `ASK_RENDEZVOUS_CEILING` (défaut **4 h**, env `IDEA_ASK_RENDEZVOUS_CEILING_MS`).
|
||||
- **Wiring** : sonde optionnelle `AskActivityProbe` injectée dans `McpServer` (modèle `events`/`ready_sink`, additif → zéro régression), branchée par la composition root `crates/app-tauri/src/state.rs` (qui résout nom→AgentId→run-dir via nouveau `service.resolve_agent_id_by_name`). Infra reste libre d'`AgentId`.
|
||||
- Fichiers : `server.rs`, `jsonrpc.rs`, `mcp/mod.rs`, `lib.rs`, `inspector/claude_paths.rs`+`mod.rs`, `application/.../service.rs`, `app-tauri/state.rs`.
|
||||
|
||||
## Validation (preuve réelle, Main)
|
||||
`cargo test -p infrastructure --lib` = **251 passed/0** (dont 6 nouveaux tests : silence→no-reply, fallback sans probe→no-reply, active→extension puis resolved, active→ceiling, codes/retryable distincts). `mcp_server` 22/0, `inspector_claude` 4/0, `cargo test -p application` tout vert. `clippy -p infrastructure -p application --all-targets` = **0 warning nouveau** (résiduels pré-existants : input/mod.rs, lifecycle.rs, fileguard.rs, server.rs:132 ready_sink). **AppImage rebuildée 2026-06-24 09:21**, installée sur `/home/anthony/Documents/IdeA_0.3.0_amd64.AppImage`, backup `….old-pre-t7-fix` (08:41).
|
||||
|
||||
## Reste à faire
|
||||
1. **Validation live T7** après relance IdeA : déléguer une tâche lourde >600 s ; attendu = pas d'expiration tant que la cible écrit son transcript, et soit résolution normale, soit (si >4 h) message ceiling-active non-retryable distinct ; idea_reply tardif non perdu tant qu'on n'a pas atteint le plafond.
|
||||
2. **Commit par Git** (non fait — laissé à Git, cf. [[git-owns-commit-merge-decisions]]) : décider de le faire avant ou après la validation live T7.
|
||||
3. Reprise complète des tests **depuis T1** (skill mcp-rendezvous-functional-test). État pré-relance : T1→T6 verts cette passe, dont fix T5 validé live (cf. [[checkpoint-mcp-tests-t1-t5-and-t5-livestate-defect]]).
|
||||
|
||||
Lié à [[rendezvous-no-reply-backstop-design]], [[backstop-fires-on-intra-task-turn-rootcause]], [[mcp-functional-test-plan-2026-06-24]].
|
||||
14
.ideai/memory/rendezvous-no-reply-backstop-design.md
Normal file
14
.ideai/memory/rendezvous-no-reply-backstop-design.md
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
name: rendezvous-no-reply-backstop-design
|
||||
description: Décision d'architecture sur la fin-de-tour et le backstop no-reply du rendez-vous idea_ask_agent ⇄ idea_reply, après échec live du fix Finding A (77e62e5).
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
Le watcher prompt-ready PTY (`infrastructure/src/input/mod.rs` `arm_prompt_watcher`) ne peut PAS servir de signal de fin-de-tour : il est one-shot ré-armé seulement au `bind_handle`, et matche un bandeau TUI **permanent** (`? for shortcuts`) — donc inopérant par tour. Preuve live : aucun `prompt_ready` de toute une session alors que l'agent a travaillé ⇒ c'est le handshake MCP `initialize` (→ `release_agent_cold_start`) qui libère le cold-start, pas le PTY.
|
||||
|
||||
**Contrat figé** : `idea_ask_agent` est garanti libéré en temps borné par l'un de :
|
||||
1. `idea_reply` (chemin propre, renforcé par le préambule comportemental injecté à chaque délégation) ;
|
||||
2. backstop no-reply sur **stagnation** — transition `Alive→Stalled` (lot-2 `arm_liveness`/`sweep_stalled`) du `Busy{ticket}` ⇒ résolution synthétique « cible silencieuse sans idea_reply » + libération du demandeur ;
|
||||
3. timeout absolu **fini** (dernier recours) — `ASK_RENDEZVOUS_TIMEOUT` ne doit JAMAIS être 24h ; défaut reco 600 s, env-overridable, garde `Some(0)=no-override`. La borne applicative per-tour (`resolve_turn_timeout`) doit aussi être finie.
|
||||
|
||||
Le scraping d'octets ANSI bruts est interdit comme autorité de fin-de-tour (fragile, profil-spécifique). Cold-start = signal MCP `initialize`. Aucun port domaine ni contrat de cartographie n'est touché : tout est infrastructure/application (réutilise lot-2 + sink MCP). Diagnosticabilité : les logs d'armement/bind doivent être en `diag!` (pas `eprintln!`→/dev/null) pour observer armement vs match.
|
||||
39
.ideai/memory/resume-after-appimage-rebuild-mcp-e2e.md
Normal file
39
.ideai/memory/resume-after-appimage-rebuild-mcp-e2e.md
Normal file
@ -0,0 +1,39 @@
|
||||
---
|
||||
name: resume-after-appimage-rebuild-mcp-e2e
|
||||
description: memory note resume-after-appimage-rebuild-mcp-e2e
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
name: resume-after-appimage-rebuild-mcp-e2e
|
||||
description: Point de reprise — programme live-state CLOS+RELEASÉ (0.3.0), discordance .gitignore D19-4 TRANCHÉE. Prochain chantier = validation MCP e2e UX. Chantiers restants priorisés.
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# Reprise — état au 2026-06-22 (run a6ced819)
|
||||
|
||||
## Où on en est
|
||||
- **Programme live-state / persistance CLOS et RELEASÉ** : `develop` @ `36be0cb` (LS8), `main` @ `29232dd` = `release(0.3.0): intègre develop dans main`. Détail : [[live-state-persistence-program-closed-ls8]]. Doc : `docs/LS8-live-state-persistence-closure.md` + `ARCHITECTURE.md` §21.
|
||||
- **AppImage rebuildée + tournante** : `IdeA_0.3.0_amd64.AppImage` (le nom n'est plus 0.1.0). Le binaire live embarque tout le programme ; 6 ponts MCP connectés/ESTAB observés → point 1 du chantier e2e (agent voit ses outils MCP sans action manuelle) déjà satisfait en réel. Recette rebuild (rappel) : `npm --prefix frontend run build` puis depuis `crates/app-tauri/` `APPIMAGE_EXTRACT_AND_RUN=1 NO_STRIP=1 ../../frontend/node_modules/.bin/tauri build --bundles appimage` ; remplacer l'AppImage installée → relancer.
|
||||
- **Discordance .gitignore ↔ D19-4 : TRANCHÉE** (par l'utilisateur) et exécutée par Git → commit `47b3806` sur `develop` (`chore(gitignore): désuivre .ideai/conversations/`). Périmètre réel : seul `.ideai/conversations/` était discordant (16 fichiers suivis, 8 handoff.md + 8 log.jsonl) ; `.ideai/run/` et `.ideai/live-state.json` étaient déjà ignorés/propres. Désuivis (rm --cached, conservés sur disque) + règle ajoutée `.gitignore:58`. Plus une décision en attente.
|
||||
|
||||
## Prochain chantier (priorité 1) : VALIDATION MCP END-TO-END UX
|
||||
Objectif = valider/durcir en situation RÉELLE le parcours inter-agents (le code est probablement bon, Bugs 1→7 corrigés cf. [[mcp-bridge-and-delegation-runtime-notes]], mais ces bugs ne sont apparus qu'en live). À vérifier sur l'AppImage 0.3.0 :
|
||||
1. Un agent lancé par IdeA voit ses outils MCP sans action manuelle. (déjà OK observé)
|
||||
2. Délégation vers agent FROID et vers agent BACKGROUND (node_id None) : tâche bien écrite dans le PTY, pas de 1er tour perdu, pas de `Busy` fantôme après interruption/annulation (Bugs 3/4/6/7).
|
||||
3. Un `ask` sans réponse ne wedge pas la connexion du demandeur (Bug 5).
|
||||
4. Profils Claude/Codex utilisent MCP par défaut ; fallback fichier+prose cohérent sinon.
|
||||
5. Observabilité UI des délégations/replies (aujourd'hui opaque) — sujet UX.
|
||||
|
||||
**CONTRAINTE MÉTHODO** : NE PAS réparer/valider le système inter-agents VIA le système inter-agents (`idea_ask_agent`). Piloter via les **subagents natifs (outil Agent)**, et demander à l'utilisateur de faire tourner l'AppImage + observer (Main ne peut pas valider seul depuis l'intérieur). Diag live : `ss -xp | grep idea-mcp` (ponts connectés) ; `~/.claude/projects/<encoded-run-dir>/*.jsonl` (transcript ; pas de nouveau fichier = tâche jamais soumise).
|
||||
|
||||
## Autres chantiers restants (depuis [[remaining-work-idea-agent-control-ide]])
|
||||
- **Auto-update mémoire/contexte EN COURS de session** (aujourd'hui injection au lancement seulement) — priorité 1.
|
||||
- **Multi-fenêtres / déplacement d'onglet** du registre de sessions — priorité 2 (UI).
|
||||
- Optionnels différés : activation réelle du seam LLM de handoff (contrat figé ADR LS5, défaut heuristique) ; sweep périodique de rotation (idempotent, non câblé).
|
||||
|
||||
## Friction outillage notée (par Git, sans incidence résultat)
|
||||
Le `settings.local.json` du run dir a un `deny` qui bloque Edit/Write et certaines redirections Bash pour les agents en run dir isolé ; Git a dû éditer `.gitignore` via `tee -a`. À assouplir si on veut des éditions de fichiers propres côté run dir.
|
||||
|
||||
## Contrainte d'écriture (rappel)
|
||||
Main + agents en run-dir isolé ne peuvent PAS écrire l'arbre du project root (docs/, ARCHITECTURE.md, .ideai/memory/*.md fichiers) — permissions déniées. Mémoire IdeA : outil `idea_memory_write` (create/replace par slug ; pas de delete). Suppression fichiers mémoire / édition MEMORY.md / CLAUDE.md / .gitignore du project root : passer par **Git**.
|
||||
11
.ideai/memory/skills-integration-canonical-foundation.md
Normal file
11
.ideai/memory/skills-integration-canonical-foundation.md
Normal file
@ -0,0 +1,11 @@
|
||||
---
|
||||
name: skills-integration-canonical-foundation
|
||||
description: Topologie d'intégration du chantier skills agent et décision d'abandon de feature/agent-skills.
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
Le chantier « skills agent » : la fondation canonique du domaine skills est **déjà dans `develop`** (introduite par `2332b7f` : port `SkillStore`, `SkillRef` sur `ManifestEntry`, `resolve_skills` dans `LaunchAgent`, CRUD + assign/unassign, **frontend complet** `features/skills/*`).
|
||||
|
||||
- `feature/agent-skills` (A, @ef101db) = réimplémentation **obsolète et incompatible** (serde `tag="type"`, `with_updated_content`, pas de `SkillRef`/frontend). **À abandonner** — ne jamais merger, elle régresse develop.
|
||||
- `feature/agent-skill-awareness` (B, @5be8987) = **surensemble propre** de develop (sa base `8452333` est ancêtre de develop ; diff skill = +539/−3). Apporte : `Skill.description`/`effective_description`, manifeste, outil MCP `idea_skill_read` (variante domaine `OrchestratorCommand::ReadSkill`), brief « capacités IdeA » inconditionnel dans `compose_convention_file`.
|
||||
- Intégration = cherry-pick `ab34363`(+`1a10d67` squash) puis `566bff4` sur develop ; **exclure** `e93a2c1` (cold-start, superseded par `8bb832c`) et le bruit `.ideai/*` (garder seulement `.ideai/memory/feature-agent-skill-awareness-design.md`). Dropper `e93a2c1` évite tout conflit sur `input/mod.rs`. Points chauds : `lifecycle.rs`, `state.rs`.
|
||||
@ -4,7 +4,14 @@
|
||||
{
|
||||
"id": "a72dac60-641c-4417-b0d7-94b8539f817a",
|
||||
"name": "build-appimage",
|
||||
"description": null,
|
||||
"contentHash": "77cb33b978b242f6"
|
||||
},
|
||||
{
|
||||
"id": "86ea97df-1533-47e5-8809-dc2b02242567",
|
||||
"name": "mcp-rendezvous-functional-test",
|
||||
"description": null,
|
||||
"contentHash": "9fc8260f64c3b9d5"
|
||||
}
|
||||
]
|
||||
}
|
||||
42
.ideai/skills/md/86ea97df-1533-47e5-8809-dc2b02242567.md
Normal file
42
.ideai/skills/md/86ea97df-1533-47e5-8809-dc2b02242567.md
Normal file
@ -0,0 +1,42 @@
|
||||
# Skill — Test fonctionnel du rendez-vous inter-agents MCP
|
||||
|
||||
Workflow **ré-exécutable et évolutif** pour tester de bout en bout le rendez-vous `idea_ask_agent` ⇄ `idea_reply` d'IdeA, du trivial au plus tordu. À relancer après chaque rebuild qui touche l'orchestration MCP / le backstop / la live-state. **Ce plan évolue** : à chaque nouveau souci rencontré, ajoute/raffine un test Tn et note le défaut dans la section « Journal des défauts ».
|
||||
|
||||
## Principe
|
||||
- **Main est le demandeur** (`idea_ask_agent`) — test fidèle de « si je donne un message à un agent, il me répond ».
|
||||
- Doublé d'**observation externe Bash** :
|
||||
- ponts : `ss -xp | grep idea-mcp` (ESTAB) et `pgrep -af mcp-server` (2 process par requester = pont vivant).
|
||||
- transcripts : `~/.claude/projects/<run-dir-encodé>/*.jsonl` (horodatages **UTC**). Reply réel = `tool_use` idea_reply → tool_result `reply … delivered`. Wedge demandeur = transcript figé sur `tool_use` idea_ask_agent sans tool_result. 1er tour intact = 1re ligne user `parentUuid:null` = `[IdeA · tâche…]`.
|
||||
- placement : `.ideai/layouts.json` (agent présent = cellule visible ; absent = background / node_id None).
|
||||
- live-state : `idea_workstate_read` (last-writer-wins, pas temps réel).
|
||||
- Règle structurelle : **binaire qui tourne = AppImage**. Tout fix backend ⇒ **rebuild + relance** d'IdeA (tue Main). Les tests s'enchaînent SANS relance *à l'intérieur d'une même version*. Vérifier avant T1 : `stat` mtime de l'AppImage récent + `git log -1` = HEAD attendu.
|
||||
|
||||
## Setup avant T1
|
||||
1. Relancer IdeA, ouvrir le projet, **Main visible** (le demandeur).
|
||||
2. Garder **2 cellules visibles libres** + lancer **QA et DevFrontend** dans des cellules visibles (cibles chaudes).
|
||||
3. Laisser **Architect, DevBackend, Git ARRÊTÉS (froids)** : T3 teste le réveil à froid ; T9 utilise Architect+DevBackend froids.
|
||||
|
||||
## Méthode d'exécution
|
||||
On lance dans l'ordre, on **note** chaque verdict avec preuve réelle. Si un défaut **bloquant** apparaît : stop, ouvrir le cycle de fix (Architect→Git→DevBackend→QA, ou via subagents si le rendez-vous lui-même est cassé), rebuild + relance, puis **reprise depuis T1**. Un défaut **non bloquant** est consigné au Journal et on peut continuer si l'utilisateur le décide.
|
||||
|
||||
## Ordre des tests (trivial → tordu)
|
||||
- **T1 — Visibilité outils MCP.** Agent lancé par IdeA voit ses outils sans action manuelle. Vérif : pont ESTAB + 2 mcp-server par requester ; cibles froides = 0 process.
|
||||
- **T2 — Cible CHAUDE + idea_reply trivial.** ask(agent chaud, « pong via idea_reply »). Attendu : `pong` inline borné, workstate `done`, pas de busy fantôme.
|
||||
- **T3 — Réveil à FROID + idea_reply.** Cible arrêtée. Attendu : pont relancé (nouveau mcp-server), **1er tour non perdu**, reply remonte.
|
||||
- **T4 — Cible BACKGROUND (node_id None).** Cible hors layout (sans cellule visible). Attendu : même protocole, multi-tours sans perte.
|
||||
- **T5 — NO-REPLY (cible répond en prose, pas d'idea_reply).** Attendu : backstop libère le demandeur en temps borné avec `TargetReturnedNoReply` (retryable), **ET live-state de la cible purgée (pas de busy fantôme)**. Défaut historique #1.
|
||||
- **T6 — Délégation MULTI-ÉTAPES puis idea_reply.** Cible lit plusieurs fichiers / lance une cmd PUIS idea_reply. Attendu : **pas de libération prématurée** pendant le travail, rapport final livré. (Piège turn-watcher : backstop tirait au 1er tour interne ~3 s.)
|
||||
- **T7 — Tâche LOURDE > plafond** (impl + `cargo test`/clippy). Attendu : extension sur signe de vie OU message clair « cible active, plafond atteint » (≠ faux `-32001`) ; idea_reply tardif non perdu. Plafond `IDEA_ASK_RENDEZVOUS_TIMEOUT_MS` (défaut 600000).
|
||||
- **T8 — Délégations PARALLÈLES** (2 cibles en 1 tour Main). Attendu : rendez-vous multiples simultanés, multiplexage pont, 2 réponses distinctes.
|
||||
- **T9 — TRANSITIVE A→B→C** (Main→Architect, Architect délègue à DevBackend puis reply à Main). Attendu : rendez-vous imbriqués, 2 attentes simultanées sans deadlock.
|
||||
- **T10 — INTERRUPTION/annulation + reconcile reboot.** (a) Main interrompt un ask en vol → `working` cible purgé, pas de cascade, idea_reply tardif non-livrable proprement. (b) Au reboot, orphelins {working,waiting,blocked} & session morte → `idle` + `STALE_AT_RESTART_MARKER` (use case ReconcileLiveState).
|
||||
|
||||
## Critère de fin
|
||||
Tous les T1→T10 verts avec preuve réelle. Sinon : 1er défaut bloquant = corriger puis reprise T1.
|
||||
|
||||
## Journal des défauts (à enrichir au fil des runs)
|
||||
- **2026-06-24, run a6ced819 (AppImage 08:15, HEAD 1efe2f1)** — T1→T4 ✅. **T5 partiel** : backstop libère le demandeur en ~24 s (`TargetReturnedNoReply` retryable, wedge demandeur corrigé) MAIS la **live-state de la cible n'est pas purgée** : elle reste `status:"working"` jusqu'au prochain write réussi de la cible (re-délégation non bloquée, busy fantôme atténué mais présent → `idea_workstate_read` ment sur la dispo). Cause : backstop agit côté demandeur, ne réinitialise pas la live-state de la cible sur no-reply. → fix en cours.
|
||||
|
||||
## Notes / pièges observés
|
||||
- IdeA peut placer une cible réveillée en **background** même quand des cellules visibles sont libres (observé T3/T4).
|
||||
- Quand le rendez-vous MCP lui-même est suspecté cassé, **ne pas** orchestrer le fix via `idea_ask_agent` (risque de blocage) : utiliser les subagents natifs de l'orchestrateur pour analyse/fix/rebuild.
|
||||
Reference in New Issue
Block a user