ASA·Compass Étiquette de distribution

Une collection a-t-elle vécu ?

La part des pièces d'une collection encore détenues par son auteur, mesurée sur la chaîne. Ce n'est pas un jugement de valeur : c'est un fait qui se calcule, et il répond à une question précise de Karl.

mesure du 1er septembre 2026 · 1 610 collections mesurées · 70 426 requêtes

Ce que Karl a demandé

« Il va falloir une façon de distinguer les collections qui sont dans des portefeuilles qui, parfois majoritairement ou totalement, n'ont jamais quitté le portefeuille du créateur. Il n'y a pas d'intérêt à inonder l'index avec des NFT potentiellement bloqués sur le compte créateur. »

Deux mots de cette phrase commandent toute la construction : majoritairement et totalement. Ce sont deux états différents, et une étiquette qui répondrait par oui ou par non les écraserait. On mesure donc la part, et les étiquettes se déduisent de seuils qui se règlent en une ligne, sans rien recalculer.

Le chiffre qui commande la lecture du reste

L'étiquette couvre la totalité du catalogue publié : 6 119 collections sur 6 119.

Aucune collection publiée ne reste sans mesure. La catégorie inconnue existe toujours dans le module, et elle reste visible par construction, mais elle est vide.

La couverture était de 29 % quand cette page a été écrite la première fois. Les 4 333 collections manquantes ont été mesurées depuis, et la section sur le coût dit pourquoi cela a été soixante-quinze fois moins cher que je l'avais annoncé.

La règle qui commandait la lecture quand la couverture était partielle n'a pas changé pour autant : ne pas savoir n'est pas une raison de faire disparaître. Une part inconnue n'est pas une part nulle. C'est ce qui protège les collections que la prochaine croissance du catalogue ajoutera avant qu'une mesure ne les atteigne.

Ce que la mesure montre

Répartition des 6 119 collections publiées, du plus retenu au plus distribué :

ÉtiquetteCollectionsPartÀ l'arrivée dans l'index
entièrement chez son auteur 4507 %masquée par défaut
majoritairement chez son auteur 1 02317 %masquée par défaut
en partie chez son auteur 1 84730 %visible
entièrement partie chez d'autres 2 79946 %visible

« Masquée par défaut » veut dire masquée à l'arrivée dans l'index, et nulle part ailleurs : la recherche par nom, la page d'une collection et celle d'un auteur les montrent toutes. Rien n'est retiré du catalogue.

La médiane est de 2,7 % : la collection typique a bel et bien circulé, et davantage que ne le laissait croire la moitié du catalogue mesurée en premier. Ce sont les 1 473 collections des deux premières lignes, 24 % du publié, que Karl ne veut pas voir inonder l'index.

Sur l'échantillon partiel, ce chiffre était de 418. L'écart ne vient pas d'un changement de règle : les collections mesurées en dernier sont les moins connues, et elles sont plus souvent restées chez leur auteur.

Le défaut qui aurait fait disparaître des collections à tort

Les deux moitiés du fichier n'avaient pas été mesurées de la même façon, et la différence était invisible à la lecture du résultat.

La première passe comptait des unités émises. L'extension comptait des pièces. Un auteur qui garde un exemplaire sur mille d'une édition compte, pour la seconde, comme détenant la pièce entière.

Le sens de l'erreur est ce qui la rendait grave. Compter en pièces surestime la part, donc pousse une collection vers les deux étiquettes masquées par défaut. L'erreur allait exactement dans le sens que l'entrée interdit : faire disparaître.

Rhythm Mag · ses 2 pièces sur 2 sont chez son auteur, ce qui donnait « entièrement chez son auteur », donc écartée.

En unités : 2 exemplaires sur 1 000. Il en a distribué neuf cent quatre-vingt-dix-huit. Elle est visible.

398 collections changeaient d'étiquette selon la façon de compter, et 184 d'entre elles étaient écartées à tort. La part a été recalculée en unités, sans une seule requête : les montants détenus étaient déjà sur le disque, et les totaux émis dans le catalogue figé.

Le fichier porte désormais un champ baseDuCalcul sur chaque entrée, pour que la question ne se repose pas en silence à la prochaine fusion.

Le fichier qui se contredisait lui-même

Une relecture indépendante a trouvé, quelques minutes après la publication précédente, deux nombres différents pour la même chose dans le même fichier, à quelques centaines d'octets d'écart.

Ce qui était annoncéCollections masquéesSur
le bloc filtre du fichier 1 4736 119
le recompte, à partir des entrées du même fichier 1 5186 267

Les deux nombres étaient justes. Le premier portait sur les collections du catalogue publié, le second sur toutes les entrées étiquetées, qui sont 148 de plus. Le défaut n'était donc pas dans le calcul.

Il était dans la donnée : aucune entrée ne disait si elle était publiée. Le fichier annonçait un total dérivé d'une information qu'il ne contenait pas, ce qui le rendait invérifiable, et garantissait que le prochain lecteur choisirait un des deux chiffres sans savoir qu'il en existait un autre.

C'est la règle de fond du projet sous un déguisement de plus, celle qui lui a déjà coûté trois nuits : une valeur dérivée figée loin de sa source finit par contredire cette source. La correction n'était pas de recalculer plus soigneusement, mais de rendre le recompte possible depuis le fichier seul. Chaque entrée porte désormais publiee, et les deux totaux sont nommés séparément.

Les 148 entrées hors du catalogue publié ne sont pas retirées. Leur mesure est bonne, et une collection absente du catalogue aujourd'hui peut y entrer demain. On les marque, on ne les jette pas : c'est la même règle que pour les collections dormantes.

La garde, éprouvée en la faisant refuser

Le contrôle recompte chaque nombre annoncé à partir des seules entrées, et refuse l'écriture si l'un d'eux ne se retrouve pas. Il ne corrige rien : un contrôle qui réparerait en silence masquerait exactement ce qu'il est censé révéler.

Douze essais le font échouer volontairement, chacun d'une façon différente. Le plus important reproduit le défaut réel : un bloc compté sur toutes les entrées au lieu des seules publiées. Le contrôle répond « annoncé 1 518, recompté 1 473 ». Un contrôle qu'on n'a jamais vu refuser ne prouve rien.

L'endroit jumeau, qui était plus dangereux

Le même motif existait une marche plus loin : cette page écrit ses nombres à la main. Le jour où le fichier change sans que la page suive, la page ment et rien ne proteste.

Chaque chiffre affiché ici est désormais rattaché à sa source dans le fichier, et une divergence refuse la publication. Le contrôle a été éprouvé de la même façon, en faussant un chiffre de la page et en vérifiant qu'il refuse. Sa limite est dite plutôt que tue : un chiffre ajouté à la page sans être inscrit dans le contrôle ne déclencherait rien.

Le cas qui a fait naître la demande

Karl a formulé sa demande en découvrant PixelKitten. La mesure lui donne raison, et elle montre au passage pourquoi une adresse ne suffit pas :

PixelKitten · 2 508 pièces · 53,4 % encore chez son auteur · réparties sur 12 portefeuilles

L'auteur n'est pas une adresse, c'est un groupe. Une pièce passée d'un portefeuille de l'auteur à un autre n'a pas quitté l'auteur. Sans cette précaution, PixelKitten aurait été déclarée largement distribuée alors que rien n'a bougé : ses 1 340 pièces retenues sont éparpillées sur douze comptes qui sont tous les siens.

Le cas n'est pas isolé : 509 collections du fichier existent en morceaux sous plusieurs portefeuilles du même auteur, et l'une d'elles en compte seize.

L'extension n'a pas pu unir ces groupes. Elle a interrogé chaque créateur pour les seules pièces qu'il avait créées, et une pièce passée à un autre portefeuille de l'auteur y compte donc comme partie. 769 entrées sont dans ce cas et portent un champ groupeNonUni.

Cette limite est dite plutôt que corrigée, et elle est tolérable pour une raison précise : elle sous-estime la part. Elle laisse visible, elle ne cache pas. C'est l'inverse du défaut précédent, et c'est pourquoi l'un a été corrigé avant publication et l'autre documenté.

Les extrémités, et ce qu'elles ont donné

La collection d'une seule pièce n'existe pas

L'entrée demandait de traiter ce cas. Vérification faite, il n'y en a aucune, ni parmi les 6 267 entrées étiquetées ni dans les 16 150 collections de la base. Une pièce isolée n'est jamais constituée en collection par la chaîne de traitement.

Le garde-fou reste utile pour son voisin immédiat : 2 560 collections publiées comptent moins de cinq pièces, et leur part ne peut y prendre qu'une poignée de valeurs. Elles sont marquées comme telles, parce que « entièrement chez son auteur » dit beaucoup moins pour trois pièces que pour cent. La proportion a beaucoup monté avec l'extension : les petites collections sont précisément celles que la première passe n'avait pas atteintes.

La pièce immobilisée dans un contrat mort

C'est l'extrémité la plus sérieuse. Une pièce qui a quitté son auteur a pu partir chez un collectionneur, s'immobiliser dans le contrat d'une place de marché fermée, ou être brûlée. Les trois se ressemblent vues d'ici : dans les trois cas, l'auteur ne l'a plus.

Un signal calculable sans réseau repère les profils suspects : peu de détenteurs, aucun joignable, et l'auteur dépossédé. 65 collections publiées présentent ce profil. Ce n'est pas une preuve, et le mot retenu dans la donnée est soupconImmobilisation.

Une seconde passe tourne en ce moment pour lever cette limite. Elle conserve, pour chaque pièce, quels comptes la détiennent : c'est le lien que la passe précédente avait payé puis jeté.

Ce lien permettra de repérer les comptes qui détiennent des pièces de dizaines de collections sans rapport, profil qui distingue un contrat de place de marché d'un collectionneur, et cela sans requête supplémentaire.

L'auteur qui a racheté ses pièces

Indétectable à partir d'un état : racheter laisse une trace dans l'historique, pas dans le solde. Une collection rachetée ressemble exactement à une collection jamais vendue. Il faudrait suivre les transferts, ce que la mesure actuelle ne fait pas.

La troisième catégorie : ce que le lien conservé a donné

K-20 demandait de distinguer une pièce partie chez un collectionneur d'une pièce immobilisée dans le contrat d'une place de marché morte. La seconde passe a relevé, pour chaque pièce, quels comptes la détiennent : c'est le lien que la passe du matin avait payé puis jeté.

Le relevé des détenteursMesuré
pièces relevées28 620
collections couvertes4 333
comptes détenteurs distincts15 613
requêtes57 240

Le résultat va contre l'hypothèse de départ, et c'est le plus utile

L'idée était qu'un compte détenant des pièces de dizaines de collections sans rapport trahirait un contrat d'entiercement plutôt qu'un collectionneur. La mesure ne le confirme pas.

Concentration du détenteur le plus chargé d'une collectionCollections touchées
médiane42
75e centile94
90e centile153
95e centile et au-delà224

La moitié des collections ont au moins un détenteur qui en touche 42 ou plus. La concentration est donc courante, pas exceptionnelle, et un seuil bas aurait désigné presque tout le catalogue en donnant l'illusion d'un tri.

Distinguer un contrat mort d'un gros collectionneur demande la nature du compte, qu'une adresse ne révèle pas. Cela coûte une requête par compte suspect, quelques centaines au plus, et c'est la suite naturelle de ce travail. Elle n'est pas faite, et le dire vaut mieux que de la laisser croire faite.

Ce qui est stocké ne dépend d'aucun seuil

Une première version de ce module enregistrait une part calculée avec le seuil du jour. Changer le seuil aurait obligé à tout recalculer, et deux fichiers produits à des réglages différents n'auraient pas été comparables sans qu'on puisse le voir. C'est la même faute que celle qu'on évite en stockant la part plutôt qu'une étiquette.

Chaque collection porte donc concentrationMaximale, un fait et non un jugement. Tout seuil s'y applique après coup, sans réseau et sans recalcul.

La mesure ne couvre que les 4 333 collections de l'extension. Les autres portent null, jamais zéro : le lien n'y a pas été conservé et ne peut pas être reconstitué. Une concentration inconnue n'est pas une concentration nulle, et les confondre déclarerait sûres des collections qu'on n'a jamais regardées.

Un contrôle refuse d'écrire le fichier si ce null venait à être compté comme une mesure. Il a été éprouvé en le faisant refuser.

Ce que l'extension a coûté, et l'erreur d'estimation

Cette page annonçait 190 000 requêtes pour couvrir les 4 333 collections manquantes, soit une vingtaine d'heures. Le chiffre était faux d'un facteur soixante-quinze.

PasseRequêtesDuréePortée
première mesure, du 1er septembre70 4268 h 1 786 collections
estimation annoncée pour le reste≈ 190 000≈ 20 h 4 333 collections
extension réellement exécutée2 516 6 min4 333 collections

L'erreur venait d'une extrapolation faite sans décomposer la dépense. J'avais divisé le coût total de la première passe par son nombre de collections. Or 86 % de ce coût était allé à interroger les détenteurs pièce par pièce, ce que la part d'auteur ne demande pas.

Le renversement qui change tout : on ne demande pas à chaque pièce qui la détient, on demande à chaque auteur ce qu'il détient encore. Le coût cesse alors de dépendre du nombre de collections pour ne dépendre que du nombre de portefeuilles d'auteurs, qui sont 1 233.

Cette erreur a été signalée dès qu'elle a été vue, parce qu'une dépense avait été autorisée sur sa foi. Une estimation qui n'est pas décomposée en postes ne vaut rien, et celle-ci le prouve dans les deux sens : elle aurait aussi pu faire renoncer à un travail de six minutes.

On filtre, on ne retire pas

« Est-ce qu'on les retire carrément ? Ou est-ce qu'on laisse l'utilisateur les filtrer in et out ? Parce que ce n'est pas parce qu'elles n'ont jamais bougé qu'elles ne bougeront jamais non plus. »

Puis, sur le réglage : « Il devrait quand même être filtré out par défaut, quand on arrive dans l'index. »

Les deux moitiés de la décision pèsent autant. Ces 1 473 collections ne doivent pas inonder la première impression du catalogue, et elles ne doivent pas cesser d'exister. Un défaut d'affichage est une opinion sur ce qui est intéressant, jamais un jugement sur ce qui est réel.

La raison de Karl porte plus loin que sa décision : cette mesure décrit un état à un instant, pas une propriété. Une collection dormante peut se vendre le lendemain de la mesure, et un index qui l'aurait retirée ne s'en apercevrait jamais.

Un mot de la donnée a changé pour cela. Le champ s'appelait ecarteeParDefaut, qui décrit une admission. Il s'appelle masqueeParDefaut, qui décrit un affichage. Le mot comptait : il aurait fini par décrire ce que le code faisait.

Les cinq endroits où le défaut ne s'applique pas

C'est là qu'est le travail, et non dans le filtre. La règle est exécutable plutôt qu'écrite en prose, parce qu'une règle en prose finit par n'être appliquée qu'aux endroits dont on se souvient. Chaque ligne ci-dessous est jouée sur le vrai catalogue par epreuve_filtre.mjs.

ContexteLe filtre s'y appliquePourquoi
arrivée dans l'indexoui, par défaut c'est la première impression
recherche par nomnon qui tape un nom cherche cette collection
page d'une collectionnon une adresse partagée ne mène jamais à une page vide
page d'un auteurnon qui demande les collections d'une adresse les veut toutes

Le premier point ne se négocie pas, et c'est celui de la recherche.

Karl ne juge pas un catalogue sur des chiffres. Il l'ouvre et y cherche des collections qu'il connaît, parce qu'il collectionne les NFT Algorand de 2021 depuis cette époque. Une collection dormante qui ne répondrait pas à son propre nom serait, pour lui, indiscernable d'une collection absente, et il conclurait que le catalogue est raté alors que la donnée serait là.

L'essai porte sur un cas réel plutôt que sur un exemple fabriqué : « Sol - Project Altair », entièrement chez son auteur, donc masquée à l'index. Elle répond à son propre nom dans la recherche, et le même essai vérifie que le contexte « index » l'aurait bien masquée : sans cette seconde moitié, l'épreuve passerait même si le filtre ne faisait rien.

Deux exigences s'ajoutent, du même ordre :

Un contexte inconnu lève une erreur au lieu de filtrer en silence. C'est la différence entre une garde et une intention : le mauvais appel doit échouer bruyamment, sinon personne ne saura jamais qu'il a été fait.

L'étiquette périme, et la campagne se rejoue

Puisque la mesure décrit un état daté, elle vieillit. Chaque entrée porte sa date, et le module dit à partir de quand elle mérite d'être refaite : quatre-vingt-dix jours. Ce délai n'est pas une vérité, c'est le moment où remesurer devient moins cher que de se fier à une donnée vieillissante, et la campagne coûte six minutes.

Une mesure sans date est traitée comme périmée. On ne peut pas garantir sa fraîcheur, et la refaire coûte moins que de s'y fier à tort.

La campagne ne refait pas tout. Ce sont les dormantes qui vieillissent mal : une collection déjà entièrement partie ne redeviendra pas retenue.

rafraichir.mjs reprend les 1 518 dormantes, les périmées, et les 769 entrées dont le groupe de portefeuilles n'avait pas été uni. Soit 2 055 collections, qui ne demandent que 1 055 comptes à interroger, parce que le coût suit les portefeuilles d'auteurs et non les collections.

Le défaut du groupe se répare gratuitement au passage. On interroge exactement les mêmes comptes, on filtre seulement leurs avoirs sur les pièces de tout le groupe au lieu des seules leurs. Le nombre de requêtes ne change pas.

La commande sans argument estime sans rien demander au réseau et n'exécute rien. Il faut un --lancer explicite. Elle écrit un fichier neuf et daté : elle n'écrase ni la mesure d'origine, ni l'étiquette complète, ni le catalogue.

L'étiquette ne s'inscrit jamais en amont dans le catalogue. Elle se recalcule à l'engendrement, à partir de la mesure datée. C'est la règle de fond du projet, et elle a déjà coûté trois nuits ici sous trois déguisements différents : une donnée dérivée écrite dans un fichier qu'un autre traitement reconstruit disparaît sans lever la moindre erreur.

Le défaut de la règle, trouvé par Karl après publication

« Il y en a qui ont créé un paquet de NFT pêle-mêle, et dans le même portefeuille, à un certain point, ils ont créé une collection qui a été distribuée. Mais sur le ratio, ça passe encore comme une minorité qui est sortie. Donc ça n'invalide pas la collection en même temps. »

La mesure est juste. C'est la règle appuyée dessus qui ne l'est pas, et la distinction vaut d'être gardée : une part élevée signifie deux choses opposées que le ratio ne sépare pas. Une collection qui n'a jamais circulé, ou une collection largement distribuée dont l'auteur a gardé un gros stock, ce qui est le cas normal d'une série à gros tirage.

Masquée aujourd'huiPartPiècesDétenteurs
Templar0,9019383
Algomond0,8758289
Community0,883253
TigerChi Special0,77343156

Une collection que 383 personnes détiennent est masquée par défaut. « Community », trois pièces pour 253 détenteurs, montre le cas le plus net : sur une édition à gros tirage, la part ne dit structurellement rien.

La donnée manquait pour les trois quarts, et elle existe quand même

Le nombre de détenteurs n'est renseigné que pour 373 des 1 473 masquées : il vient de la mesure du matin, qui ne couvrait qu'une partie du catalogue. Une correction appliquée telle quelle n'aurait donc porté que sur un quart du problème, en laissant le reste masqué en silence.

Le relevé des détenteurs reconstitue les 1 100 autres, toutes, sans une seule requête. Zéro collection reste sans moyen de savoir. C'est le lien que la passe du matin avait payé puis jeté, et il sert ici à une question pour laquelle il n'avait pas été gardé.

Si l'on cesse de masquer au-delà deCollections rendues visibles
5 détenteurs404
10 détenteurs206
20 détenteurs99
30 détenteurs68

Sur les 1 100 reconstituées, 44 seulement reposent sur un échantillon : leur nombre de détenteurs est alors un minorant. La règle libérerait donc au moins ce qu'elle annonce, jamais moins.

Le seuil n'est pas choisi ici, il appartient à Karl. L'appliquer ne coûtera rien : la mesure brute est déjà stockée, ce qui est tout l'objet de l'avoir stockée ainsi plutôt que sous forme d'étiquette.

C'est la même leçon que « on filtre, on ne retire pas », une marche plus loin. Karl avait posé qu'une collection dormante ne se retire pas parce qu'elle pourrait bouger un jour. Ici, elle a déjà bougé, et le critère la masquait quand même.

Ce qui reste à faire, pour qui reprendra

rafraichir.mjs n'a jamais été lancé. Il est écrit, éprouvé à vide, et attend son tour : une autre campagne occupait l'indexeur.

Deux mesures ne sont pas faites et ne demandent que quelques centaines de requêtes : la nature des comptes les plus concentrés, seule capable de distinguer un contrat de place de marché mort d'un gros collectionneur, et le nombre de détenteurs pour les collections dont l'échantillon était partiel.

Ce que ce travail produit, et pour qui

Un fichier distribution-complete.json, indexé par l'identifiant de collection de la base, que la session qui engendre le site pourra joindre directement. Chaque entrée porte la part, l'étiquette, la date de la mesure puisqu'elle vieillit, la base sur laquelle elle a été calculée, le détail qui permet de recalculer autrement, et ce qu'on ignore.

Il est joint à cette page : distribution-complete.json, 4,1 Mo, pour que ce qui est affiché ici soit vérifiable ligne à ligne plutôt que cru sur parole.

Les seuils vivent dans le module et non dans la donnée : déplacer la frontière du « majoritairement » ne demande pas de repayer une passe de réseau. Les 1 473 collections masquées par défaut ne le sont que par le réglage actuel, et un seul nombre les fait toutes revenir. Aucune n'est retirée de l'index.

Cette étiquette ne juge pas la qualité. La note dit si une collection mérite d'être publiée, celle-ci dit si elle a vécu. Une belle série jamais distribuée reste une belle série, et Karl pourrait vouloir la montrer un jour dans un rayon à part plutôt que la cacher.

Première mesure du 1er septembre 2026, jamais relancée. Extension du même jour, sur les collections qu'elle n'avait pas couvertes. Copies figées au moment du calcul, avec leur empreinte, parce que le catalogue est réécrit par cinq modules et qu'il a bougé pendant ce travail. L'affichage dans les pages du site appartient à la session qui l'engendre : ce travail produit la donnée et la règle, pas l'écran.