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
« 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.
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.
Répartition des 6 119 collections publiées, du plus retenu au plus distribué :
| Étiquette | Collections | Part | À l'arrivée dans l'index |
|---|---|---|---|
| entièrement chez son auteur | 450 | 7 % | masquée par défaut |
| majoritairement chez son auteur | 1 023 | 17 % | masquée par défaut |
| en partie chez son auteur | 1 847 | 30 % | visible |
| entièrement partie chez d'autres | 2 799 | 46 % | 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.
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.
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ées | Sur |
|---|---|---|
| le bloc filtre du fichier | 1 473 | 6 119 |
| le recompte, à partir des entrées du même fichier | 1 518 | 6 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.
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.
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.
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é.
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.
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.
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.
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.
| Passe | Requêtes | Durée | Portée |
|---|---|---|---|
| première mesure, du 1er septembre | 70 426 | 8 h | 1 786 collections |
| estimation annoncée pour le reste | ≈ 190 000 | ≈ 20 h | 4 333 collections |
| extension réellement exécutée | 2 516 | 6 min | 4 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.
« 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.
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.
| Contexte | Le filtre s'y applique | Pourquoi |
|---|---|---|
| arrivée dans l'index | oui, par défaut | c'est la première impression |
| recherche par nom | non | qui tape un nom cherche cette collection |
| page d'une collection | non | une adresse partagée ne mène jamais à une page vide |
| page d'un auteur | non | 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.
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.
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.