Back to flin
flin

Intégration temporelle : des bugs à 100 % de couverture de tests

Le récit honnête de huit sessions de débogage, d'audit et de corrections qui ont porté le modèle temporel de FLIN d'un stub cassé à 100 % de couverture de tests.

Juste A. Gnimavo (Thales) & Claude | March 26, 2026 6 min flin
EN/ FR/ ES
flintemporaltestingdebuggingcoverage

Ceci n'est pas une histoire de succès sur un design élégant. C'est un récit de guerre sur des bugs, des hypothèses erronées, et le travail de fond pour faire fonctionner une fonctionnalité complexe. Entre les sessions 068 et 076, nous avons passé huit sessions à déboguer le modèle temporel de FLIN -- découvrant que des fonctionnalités qu'on croyait manquantes étaient en fait implémentées, que des fonctionnalités qu'on croyait fonctionnelles étaient en fait cassées, et que notre suivi de progression était terriblement inexact.

À la fin, les vingt-sept tests d'intégration temporelle passaient. Mais y arriver fut un rappel humiliant que construire une fonctionnalité de compilateur et livrer une fonctionnalité de compilateur sont deux choses très différentes.

Le point de départ : un confiant 3 %

Avant la session 068, notre document de suivi disait que le modèle temporel était complété à trois pour cent. Cinq tâches sur cent soixante. Seule la suppression douce était implémentée. Tout le reste était listé comme « non commencé » ou « minimal ».

C'était faux. Spectaculairement faux.

L'audit qui a tout changé

La session 068 a commencé comme une évaluation de routine. Au lieu de cela, elle est devenue une expédition archéologique.

Le modèle temporel n'était pas complété à trois pour cent. Il était complété à trente-sept virgule cinq pour cent. Soixante tâches sur cent soixante étaient déjà faites. Le lexeur avait tous les jetons. L'analyseur construisait les bons noeuds AST. Le vérificateur de types validait les expressions temporelles. Le générateur de code émettait les bons bytecodes. La VM avait des gestionnaires pour chaque opcode temporel. La base de données stockait l'historique des versions.

Le code existait. Il n'avait simplement jamais été testé de bout en bout.

Progress before audit:  5/160  (3%)
Progress after audit:  60/160  (37.5%)

Et voici ce qui était cassé :

  • OpCode::AtTime était un stub qui retournait l'entité inchangée.
  • Le vérificateur de types rejetait les chaînes de date dans les expressions @.
  • Il y avait un test d'intégration (lexeur uniquement).
  • Aucune validation bout en bout n'existait.

La leçon était douloureuse : sans tests d'intégration, on n'a aucune idée si les fonctionnalités marchent.

Le stub AtTime qui a trompé tout le monde

Le bug le plus embarrassant était OpCode::AtTime. Cet opcode gérait l'accès par mot-clé temporel. Il avait été « implémenté » dans une session antérieure. Il compilait. Il s'exécutait sans erreurs. Il retournait une valeur.

Il retournait la mauvaise valeur. L'implémentation était un stub :

rust// The original "implementation"
OpCode::AtTime => {
    let _time_code = self.read_u8(code);
    let entity_val = self.pop()?;
    // Just return the entity unchanged
    self.push(entity_val);
}

Lire l'octet de code temporel. Dépiler l'entité. La rempiler. Pas de calcul d'horodatage. Pas de recherche d'historique. Si vous écriviez user @ yesterday, vous obteniez l'utilisateur d'aujourd'hui.

Session 076 : la poussée finale vers 100 %

La session 076 fut le point culminant -- corriger les onze échecs restants pour atteindre cent pour cent de couverture de tests temporels. Chaque échec avait une cause racine différente.

Cause racine 1 : blocs {if} au niveau supérieur (7 tests). Sept tests échouaient parce que les blocs {if} étaient écrits au niveau supérieur du fichier. Dans FLIN, les jetons de flux de contrôle comme {if} ne sont reconnus par le lexeur qu'à l'intérieur d'éléments de vue (mode Content).

Cause racine 2 : conflit de mots-clés réservés (2 tests). Deux tests utilisaient log comme nom de variable. Dans FLIN, log est une fonction intégrée.

Cause racine 3 : delete crée une version (1 test). Un test attendait deux versions après deux sauvegardes, mais delete crée une troisième version.

Cause racine 4 : rendu réactif (4 tests). Le rendu HTML de FLIN enveloppe les valeurs interpolées dans des spans réactifs, ce qui cassait les assertions de test.

Ce que nous avons appris

1. Toujours auditer avant de supposer

La session 068 a révélé que la progression était douze fois plus élevée que ce que l'on croyait. Du code avait été écrit dans des sessions précédentes et jamais suivi.

2. Les tests d'intégration sont non négociables

Les tests unitaires à chaque couche passaient. Mais le flux bout en bout était cassé parce qu'AtTime était un no-op. Seuls les tests d'intégration ont détecté cela.

3. Les échecs de tests ne portent souvent pas sur ce qu'on croit

Des onze échecs corrigés en session 076, zéro étaient causés par des bugs de logique temporelle. Sept étaient des problèmes de syntaxe de vue. Deux étaient des collisions de mots-clés. Le modèle temporel lui-même était correct -- les tests ne l'étaient pas.

4. La clarté sémantique prévient les bugs

Le bug de duplication d'historique existait parce qu'il n'y avait pas de règle claire sur qui possédait la « version courante » dans la liste d'historique. Une fois la règle établie, le bug est devenu évident et la correction triviale.

Le marathon de débogage en chiffres

MétriqueValeur
Sessions passées8 (068-076)
Tâches temporelles découvertes comme déjà complètes55
Bugs trouvés et corrigés5
Tests ajoutés26
Causes racines identifiées5 catégories distinctes
Lignes de code de test~700
Régressions de tests de bibliothèque0

Le modèle temporel est passé d'une collection de code non testée à une fonctionnalité entièrement validée, couverte à cent pour cent. Ce n'était pas un travail glamour. Il n'y a pas eu de percées architecturales. Juste du débogage systématique, un échec à la fois, jusqu'à ce que chaque test passe au vert.

C'est comme ça que le vrai logiciel est livré.


Ceci est la partie 3 de la série sur le modèle temporel de « How We Built FLIN », documentant le marathon de débogage qui a porté les tests temporels à 100 % de couverture.

Navigation de la série : - [046] Every Entity Remembers Everything: The Temporal Model - [047] Version History and Time Travel Queries - [048] Temporal Integration: From Bugs to 100% Test Coverage (vous êtes ici) - [049] Destroy and Restore: Soft Deletes Done Right - [050] Temporal Filtering and Ordering

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles

Thales & Claude thales

Treize agents, quarante-trois minutes : la première session Workflow de Claude Fable 5, et ce qu'un script d'orchestration déterministe change aux builds multi-agents

Un prompt, treize agents, quarante-trois minutes : la première session de production avec Claude Fable 5 et l'outil Workflow de Claude Code a livré un site web de production complet de sept pages plus un endpoint backend de capture de leads, en un seul commit. Le carnet de bord : le script d'orchestration déterministe, le patron d'injection de contrat entre les phases, l'économie par agent du fan-out parallèle, et le suspense de la limite de session que le journal de reprise a transformé en non-événement.

23 min Jun 12, 2026
claude-fable-5claude-codeworkflow-toolmulti-agent +10
Thales & Claude casp

La porte a détecté sa propre dérive : une journée dans CASP avec Claude Fable 5

Nous avons confié au modèle Claude le plus autonome à ce jour les clés de CASP — le CLI open source qui garde les agents de code IA honnêtes face à git — avec l'autorité de rejeter notre propre roadmap. Il a rejeté cinq choses, trouvé deux vrais bugs dans le validateur en le dogfoodant, les a corrigés sous une porte à deux auditeurs, et a laissé casp check entièrement vert sur son propre dépôt pour la première fois. CASP 0.3.0 en est le résultat.

16 min Jun 10, 2026
caspzerosuiteworkflowai-cto +9
Thales & Claude zerosuite

La transplantation du CASP : comment la discipline des six fichiers est passée de Conductor à un ERP transport anti-fraude, ce que la compétence /next ajoute quand l'opérateur tape juste « next », et pourquoi le coût d'une dérive du CASP grimpe quand le projet, c'est l'argent des autres

La discipline du CASP qui a piloté trente-cinq sessions de Conductor est agnostique au produit. Le carnet de bord de sa transplantation sur KASSIA, un ERP transport anti-fraude pour un exploitant de flotte en Côte d'Ivoire : ce qui a migré, ce qui n'a pas migré (le validateur sur mesure — et ce que son absence coûte), ce que la compétence /next ajoute quand l'opérateur tape un seul mot, et là où le CASP s'arrête — le bug de déploiement qu'il ne pouvait pas voir parce qu'il enregistre l'intention, pas la réalité de l'infrastructure.

23 min Jun 8, 2026
kassiaerp-kassia-transport-logistiquezerosuiteCASP +15