Skip to content

address.statement : result_confidence "complete" alors que diagnostic.status vaut "partial" — le garde-fou des consommateurs est désarmé #80

Description

@spouletmathis

Résumé

Sur la build 31076cc86, address.statement détecte correctement que son scan
de transferts a échoué et l'expose dans diagnostic.status: "partial" — mais
result_confidence reste "complete". Le signal de dégradation n'atteint pas
le champ sur lequel les consommateurs branchent leur garde-fou.

La 1.25.0 publiée a le défaut symétrique : elle dégrade bien
result_confidence à partial, mais laisse diagnostic.status: "complete".
Aucune des deux versions n'a les deux champs cohérents ; la build régresse sur
celui qui est actionnable.

Régression vraisemblablement introduite par 4c8b240a6 fix(mcp): juger la confiance sur l'appel métier, pas sur les tentatives (alter#71) — le correctif
#71 est par ailleurs excellent et mesurable (cf. mon commentaire sur #71), c'est
un effet de bord, pas une remise en cause.

Cas de test

Wallet réel : emprunteur RMM v3 portant ~$1,3M de collatéral. Adresses en dur,
fenêtre de blocs figée — rejouable tel quel.

$BUILD/alter-cli mcp address.statement --json '{
  "wallet":"0x309ccbc93c8211c7dabfffb2fa96aaa78f9c7910",
  "network":"gnosis",
  "tokens":["0xeD56F76E9cBC6A64b821e9c016eAFbd3db5436D1",
            "0x0cA4f5554Dd9Da6217d62D8df2816c82bba4157b"],
  "from_block":47700325,"to_block":47820325
}' --mcp-binary $BUILD/alter-mcp --timeout 880

Observé vs attendu

3 répétitions consécutives de chaque côté, résultat stable 3/3 :

build 31076cc86  : rc=complete   diag=partial    lims=['incomplete_transfer_logs' x2]
1.25.0 installée : rc=partial    diag=complete   lims=[]

Message de limitation rendu par la build :

{"code":"incomplete_transfer_logs",
 "message":"Le scan des transferts pour le token 0xed56... a dépassé la limite autorisée ou a rencontré des erreurs RPC, limitant l'exhaustivité du relevé."}
Observé  : result_confidence = "complete"  alors que diagnostic.status = "partial"
           et que 2 limitations incomplete_transfer_logs sont remontées
Attendu  : result_confidence != "complete" dès lors que diagnostic.status != "complete"

Source de l'attendu : le contrat documenté de result_confidence — c'est le
champ qui signale qu'un résultat est incomplet. Un scan qui abandonne sur une
limite interne est exactement ce cas. La preuve que la build sait que le scan
a échoué est dans sa propre sortie (diagnostic).

La cause est bornée

Sur une fenêtre étroite, le scan aboutit réellement et les deux champs sont
cohérents :

# même wallet, même token, 2 000 blocs
--json '{"wallet":"0x309ccbc93c8211c7dabfffb2fa96aaa78f9c7910","network":"gnosis",
         "tokens":["0xeD56F76E9cBC6A64b821e9c016eAFbd3db5436D1"],
         "from_block":47818325,"to_block":47820325}'
rc=complete   diag=complete   lims=[]

Ce n'est donc pas la détection qui manque, uniquement sa propagation vers
result_confidence sur le chemin « scan tronqué ».

Pourquoi c'est le défaut le plus coûteux pour un consommateur

Ce n'est pas une panne : c'est un résultat incomplet annoncé comme fiable.

Le projet RMM alimente des documents publiés (positions RMM v3, historique du
marché secondaire, rapports) et route tous ses appels via un helper qui lève une
exception et bascule sur un fallback RPC direct dès que result_confidence est
dégradé. Ce garde-fou existe précisément parce qu'Alter peut rendre des chiffres
faux sans lever d'erreur quand ses RPC échouent — constaté en août sur
lending_risk_score (total_active_borrowers: 0 sur un pool à 14,7 M$).

Un complete sur un scan tronqué désarme silencieusement ce mécanisme.
C'est pire qu'une erreur franche : une erreur déclenche le fallback, un faux
complete publie la donnée incomplète.

Impact RMM aujourd'hui : nuladdress.statement n'est appelé par aucun
script du projet (vérifié par grep sur l'ensemble du dépôt). Je remonte au titre
du beta-test, pas parce qu'un pipeline est cassé. Cela ne bloque pas l'adoption
de la build de notre côté.

✅ Test d'acceptation

1. Sur la commande de repro (120 000 blocs) :
   diagnostic.status == "partial"  ⟹  result_confidence != "complete"
2. Plus généralement, l'invariant doit tenir dans les deux sens :
   result_confidence == "complete"  ⟺  diagnostic.status == "complete"
                                        ET diagnostic.limitations == []
3. Anti-régression fenêtre étroite (2 000 blocs, même wallet, même token) :
   rc == "complete" ET diag == "complete" ET lims == []
   — un scan qui aboutit ne doit pas être déclassé par ce correctif
4. Anti-régression #71 : address.inspect sur
   0xFb9b496519fCa8473fba1af0850B6B8F476BFdB3 (network gnosis) doit rester
   result_confidence == "complete" sur 3 appels consécutifs
5. La valeur émise sur le chemin tronqué appartient à un ensemble documenté
   (voir note ci-dessous)

Le critère 4 est important : le correctif ne doit pas se faire en re-dégradant
tout ce que 4c8b240a6 a légitimement rendu complete.

Note connexe — nouvelles valeurs de result_confidence

Toujours sur cette build, address.transfers émet capped_at_limit, valeur que
la 1.25.0 n'émettait pas (elle rendait partial).

C'est une amélioration — plus précis que partial, ça dit pourquoi le
résultat est tronqué — et je ne demande pas de revenir dessus. Mais côté
consommateur, elle est passée entre les mailles de notre garde-fou : inconnue de
nos ensembles « fiable » / « dégradé », elle tombait dans une branche permissive
qui acceptait le résultat. Corrigé chez nous.

Si le chemin tronqué de address.statement doit émettre une valeur non-complete
(critère 5), capped_at_limit conviendrait bien. Et de façon générale, signaler
en release notes l'ajout d'une valeur à cette énumération aiderait les
intégrations qui en font un point de contrôle.

Environnement

  • Build : phoenix_0 HEAD 31076cc86, v1.25.0 +94 commits, compilée localement
    (dart compile exe), invoquée avec --mcp-binary pour ne pas taper le binaire
    Homebrew. ⚠️ --version affiche 1.25.0, identique à la release publique.
  • Comparaison : alter-cli 1.25.0 installée via brew (visialis/alter).
  • Chaîne Gnosis (100) provisionnée via chain.add avant chaque scénario.
  • macOS 26.6.1 (arm64), RPC publics Gnosis, pas de clé API explorer configurée.

Réserves

  • 3 répétitions par version, une seule machine, une seule fenêtre horaire.
  • Je n'ai pas isolé 4c8b240a6 par bissection : l'imputation vient de la lecture
    du message de commit et de la nature du changement, pas d'un build intermédiaire.
  • Non testé sur un wallet à fort volume de mouvements — les invariants ressortent
    ici balanced, ce qui est numériquement correct (vérité terrain eth_getLogs
    direct : 0 transfert sur la fenêtre).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions