Cache : la ligne MCP du préambule ne manque plus au premier tour après un démarrage

Le préambule système était bâti (InjectSkills → baseSystemPrompt) AVANT que
runChat n'appelle EnabledTools, donc avant que mcpTools n'ouvre les connexions.
mcpPromptLine lisait le pool encore vide : le premier tour après un démarrage
partait sans la ligne MCP, le second avec — tout le prompt à recalculer pour
une ligne. Elle comptait en plus les outils masqués par l'utilisateur, et
s'affichait pour le planner, qui ne reçoit aucun outil MCP.

- prepareTurn calcule les outils UNE fois par tour, puis le préambule à partir
  d'eux ; runChatTools les reprend tels quels (pas de second passage par
  mcpEnsureAll, qui retentait deux fois un serveur en panne).
- mcpPromptLine se déduit de cette tranche : seuls les outils réellement
  envoyés sont comptés, et rien n'est annoncé sans outil MCP.
- trackerList départage les égalités d'horodatage par nom puis slug : la liste
  part dans le contexte, un ordre tiré au sort changeait le prompt.
- Le commentaire de tasks_run.go ne prétend plus que le préfixe d'une tâche
  égale celui du chat (dossier de travail et taskCaps diffèrent).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Opus 5.5 committed 2026-10-04 01:31:00 +02:00
1 parent 9263df404d
commit 7dd319a058
12 files changed
+202 -34

No files matched your search

+29
View File
@@ -289,3 +289,32 @@ func TestStrTolerantAuType(t *testing.T) {
t.Fatalf("str(\"texte\") = %q", got)
}
}
// Deux trackers au même horodatage (points datés du même jour, sans heure)
// sortent toujours dans le même ordre — par nom — quel que soit l'ordre de
// parcours du stockage. La liste part dans le contexte du modèle : un ordre
// tiré au sort changerait le prompt d'un tour à l'autre.
func TestTrackerListOrdreStableAEgalite(t *testing.T) {
newProjectHome(t)
ensureDefaultProject()
for _, name := range []string{"zinc", "azote", "magnésium"} {
if _, err := trackerAdd(name, "2026-05-04", "1"); err != nil {
t.Fatal(err)
}
}
if _, err := trackerAdd("récent", "2026-06-01", "2"); err != nil {
t.Fatal(err)
}
want := []string{"récent", "azote", "magnésium", "zinc"}
for round := 0; round < 20; round++ {
list := trackerList()
var got []string
for _, m := range list {
got = append(got, m.Name)
}
if strings.Join(got, ",") != strings.Join(want, ",") {
t.Fatalf("ordre %v, attendu %v (le plus récent d'abord, puis par nom)", got, want)
}
}
}