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.

Thales & Claude | March 30, 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