diff --git a/DECISIONS.md b/DECISIONS.md index 5b92107..604287a 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -440,3 +440,43 @@ silence, pas de réimplémenter JSON Schema. Le renommage des paramètres (`entity_type`/`query` uniformisés) a été **écarté** au profit de cette validation — voir ROADMAP « Écarté ». + +--- + +## D24 — Contrat de troncature : borné + signalé, jamais un rejet silencieux + +**Piège mesuré (24-25/08/2026).** Une réponse d'outil de ~70 000 caractères +(`get_system_parameters` sans filtre ; `search_logs` atteignait 52-56 000 avec +les seuls défauts) est **rejetée par le client MCP** — l'utilisateur voit un +échec opaque au lieu d'un résultat partiel. + +**Décision.** Tout outil susceptible de produire une sortie volumineuse borne +sa réponse et **signale** la coupe. Le signal est commun : + +| Champ | Sémantique | +|---|---| +| `truncated: true` | présent **uniquement** quand la réponse a été coupée — jamais `truncated: false` | +| `hint` | présent ssi `truncated` ; actionnable : dit comment continuer (`offset` suivant) ou réduire (filtres, `context_lines`…) | +| `returned` | nombre d'éléments effectivement renvoyés | +| total (`totalParameters`, `totalResults`) | total **avant** la coupe — `truncated` se vérifie donc depuis la réponse elle-même | + +Les mécanismes restent **volontairement locaux**, car ils diffèrent : +`get_system_parameters` pagine (`limit`/`offset` au schéma — rien n'est perdu, +on continue avec l'offset suivant) ; `search_logs` plafonne le volume +(`MAX_LOG_SEARCH_CHARS`, défaut 25 000 caractères) en écartant des résultats +**entiers** — jamais coupés au milieu de leurs lignes de contexte — et annonce +en plus `omitted`, le compte écarté. Pas de helper partagé : le factoriser +forcerait une abstraction commune à deux mécanismes qui n'en ont pas. + +Deux garde-fous de cadrage : + +- **Ne pas réduire les défauts existants** (`max_results` 50, `context_lines` 2) + pour passer sous le plafond : le correctif est le bornage signalé, pas un + changement silencieux de comportement. +- La taille qui fait foi est celle de `content[0].text` **mesurée via le + protocole**, pas une estimation. Ordre de grandeur cible : ~20-25 000 + caractères par réponse. + +Au passage, `totalParameters` a changé de sens : c'était le nombre brut +d'entités `Parameter` chargées, c'est désormais le total correspondant aux +filtres avant pagination (identique sans filtre). diff --git a/ROADMAP.md b/ROADMAP.md index 7fda16a..59a9c48 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -12,22 +12,6 @@ contient que ce qui reste à faire. --- -## Lot 3 — Ergonomie et documentation - -Le lot 2 (résolution `Name` -> `TableName`, rejet des paramètres inconnus, -garde-fous d'arguments manquants) est livré — voir **D21** et **D23**. - -### L3.1 — Bornage des sorties volumineuses - -- `get_system_parameters` : ajouter `limit` / `offset`, aujourd'hui absents - (sortie constatée : 70 000 caractères, rejetée par le client). -- `search_logs` : garde-fou de taille. `max_results` existe déjà, mais les - `context_lines` multiplient le volume (88 000 caractères pour 50 résultats). -- Renvoyer `truncated: true` explicitement plutôt que de laisser le client se - faire rejeter. - ---- - ## Lot 4 — Modèle de données et applications Deux angles morts constatés le 24/08/2026, plus larges que les lots 2 et 3. Les @@ -151,7 +135,7 @@ La référence de l'API documente des champs que le MCP n'envoie jamais : | `Parameters` | requêtes **paramétrées** (dictionnaire `nom -> {TypeName, Value}`) — supprimerait toute concaténation de chaîne dans les filtres, et pourrait débloquer D13 (`Select`) | | `CommandTimeout` | timeout par requête, au lieu du timeout HTTP global de 30 s | | `QueryId` + `POST /QueryCancel` | annulation d'une requête longue | -| `POST /QueryExecuteStream` | résultats en flux — piste sérieuse pour L3.1 (sorties volumineuses) | +| `POST /QueryExecuteStream` | résultats en flux — piste long terme pour les sorties volumineuses, au-delà du bornage signalé de D24 | Autres endpoints jamais utilisés, à évaluer : `QueryEvents`, `QueryCommands`, `QueryCorrelationEvents`, `QuerySnapshots` (event sourcing — utile en debug),