Aller au contenu

Le modèle de faits

Toute la valeur d'AIM tient dans un choix : l'extraction produit des objets typés, pas du texte libre.

Un résumé de documentation est agréable à lire et ne change rien à ce que l'agent écrit. Un fait typé, scopé et sourcé change son comportement.

Le test appliqué à chaque fait

Le prompt d'extraction impose une question unique :

Si un développeur compétent mais nouveau chez ce client ignorait ce fait, produirait-il un travail différent, ou se ferait-il reprendre en revue ?

Si la réponse est non, le fait n'est pas extrait. Mieux vaut trois faits tranchants que vingt faits tièdes.

Sont explicitement écartés : la connaissance générale (« il faut écrire des tests »), les reformulations du document, tout ce qu'un bon développeur sait déjà.

Les huit types

Type Question à laquelle il répond
stack Quelles technos, quelles versions, pour quel rôle ?
convention Comment écrit-on du code qui passe la revue ici ?
architecture Pourquoi c'est structuré comme ça ?
runbook Comment on livre, release, rollback, débogue ?
constraint Qu'est-ce qui est interdit (sécurité, conformité, SLA) ?
pitfall Quel piège a déjà coûté cher à quelqu'un ?
glossary Que veut dire ce terme interne ?
contact Qui possède quoi ?

Ces huit types ne sont pas une taxonomie exhaustive du savoir : ce sont les huit questions qu'un agent se pose avant d'écrire une ligne.

Anatomie d'un fait

{
  "id": "nordwind:constraint:7f3a91c2",
  "type": "constraint",
  "statement": "Ne jamais modifier un script de migration Flyway déjà mergé sur main : Flyway valide les checksums et le déploiement échouera en production.",
  "detail": "Crée toujours une nouvelle migration `V<n>__<description>.sql` dans `db/migration/`.",
  "scope": ["db/migration/**"],
  "tags": ["database", "flyway", "migration"],
  "confidence": 0.95,
  "status": "candidate",
  "provenance": [
    {
      "document_id": "nordwind:file:d68deeeb4b",
      "origin": "guide-dev-backend.md",
      "quote": "Ne modifie jamais un script de migration déjà mergé sur main"
    }
  ]
}

statement

Une phrase, impérative, autonome. Elle sera lue hors de tout contexte : elle doit se suffire à elle-même.

Bon « Les migrations passent par Flyway ; ne jamais modifier un script déjà mergé. »
Mauvais « Le document parle de la gestion des migrations. »

scope

Les globs auxquels le fait s'applique — internal/api/**, **/*_test.go. Vide signifie « partout ».

C'est ce champ qui permet à l'outil MCP conventions de ne renvoyer que les règles concernant le fichier en cours d'écriture, au lieu de charger tout le contexte du client.

Une portée universelle est une absence de portée

Un ** explicite est retiré à la compilation. Conservé, il ferait passer la règle pour spécifique à chaque fichier interrogé et noierait celles qui le sont réellement.

confidence

  • 0,9 et plus : le document l'affirme explicitement et sans ambiguïté.
  • 0,6 à 0,8 : déduit d'un exemple ou d'un usage observé.
  • 0,3 à 0,5 : inférence fragile.

La confiance sert à filtrer et à hiérarchiser, pas à décorer.

provenance

Le document et la citation verbatim qui justifie le fait. C'est la propriété la plus importante du modèle : quand l'agent applique une règle que tu juges fausse, tu remontes en un geste à la phrase qui l'a produite — et tu corriges la source, pas le pack.

Un fait sans provenance est invalide par construction.

Priorité : ce qui entre dans le pack

La place dans le pack statique est limitée. Le score de sélection donne plus de poids au type qu'à la confiance :

Type Poids
constraint 1,00
convention 0,95
pitfall 0,90
stack 0,85
runbook 0,70
architecture 0,60
glossary 0,35
contact 0,30

Une contrainte de sécurité moyennement certaine mérite mieux sa place qu'une entrée de glossaire parfaitement sûre. S'y ajoute un bonus de corroboration : un fait confirmé par plusieurs sources indépendantes monte.

Cycle de vie

stateDiagram-v2
    [*] --> candidate: extraction
    candidate --> approved: aim review
    candidate --> rejected: aim review
    candidate --> conflicting: consolidation
    conflicting --> approved: arbitrage humain
    conflicting --> rejected: arbitrage humain

Tant que aim review n'est pas entré dans les habitudes, les faits candidate entrent quand même dans le pack — un pack limité aux faits approuvés serait vide au premier jour. Ce comportement se règle par client (include_candidates).

Consolidation

Une extraction document par document produit inévitablement des redites : le guide d'onboarding et le dépôt affirment la même règle avec des mots différents.

Deux passes s'en occupent :

  1. Lexicale, automatique après chaque extraction. Rapproche les énoncés dont les vocabulaires se recouvrent largement (indice de Jaccard ≥ 0,62). Attrape les reformulations proches.
  2. LLM, à la demande via aim consolidate. Attrape les paraphrases, réécrit l'énoncé fusionné, et signale les contradictions au lieu de trancher.

Une fusion n'efface jamais une provenance : deux sources qui disent la même chose deviennent un fait à deux provenances. La corroboration devient un signal de fiabilité au lieu d'être du doublon.