Français
Journal des changements
Tous les changements apportés à Knockwire, du plus récent au plus ancien, regroupés par jour de mise en production. Il n'y a pas de numéros de version ici parce qu'il n'y a pas de versions : le produit est déployé en continu, et la date est donc la seule étiquette honnête. La liste commence au premier commit, le 29 juillet 2026. L'entretien courant n'y figure pas. Tout ce qui a changé ce que le produit fait, ou ce qu'il affirme de lui-même, y figure.
Cinq langues, et plus aucune boîte aux lettres publiée
- AjoutéLes pages marketing, les trois documents juridiques et le blog existent désormais en japonais, portugais du Brésil, espagnol et français en plus de l'anglais. Chaque page est canonique vers elle-même, avec des hreflang réciproques. Une page non traduite n'a ni route ni entrée hreflang, parce qu'un lien qui promet une langue qu'il ne sait pas servir est pire que pas de lien du tout.
- AjoutéLe blog, nos textes. Quatorze articles de fond, environ 19 000 mots en anglais, et les quatorze dans les cinq langues : 70 articles. Les graphiques sont déclarés comme des données plutôt que comme des images, si bien qu'un article traduit obtient un graphique traduit.
- AjoutéLe tableau de bord se lit en cinq langues, 246 chaînes chacune. La langue vient du compte : la changer s'applique donc sur tous les appareils à la fois, et non à la connexion suivante.
- AjoutéUn formulaire de contact. Chaque message arrive à une personne, et les adresses restent sur le serveur, où rien ne peut les lire.
- RetiréSix adresses e-mail publiées à travers le site, et une septième dans les données structurées, qui était la pire de toutes : lisible par une machine et servie sur chaque page. Un produit fondé sur le principe que lire des pages publiques à grande échelle est facile ne devrait pas s'étonner que cela nous arrive.
- CorrigéToutes les pages étaient servies comme de l'anglais. Une page en japonais était lue à voix haute par les lecteurs d'écran avec une voix anglaise, et les moteurs de recherche recevaient la même information.
- CorrigéPartager n'importe quelle page produisait la carte de la page d'accueil anglaise. Les 101 pages avaient hérité d'une seule carte sociale : une politique de confidentialité en japonais se présentait donc avec le texte de la page d'accueil.
- CorrigéUne URL sans correspondance faisait tomber le serveur au lieu de renvoyer un 404. C'était la cause des 502 intermittents, et des styles cassés que l'on nous signalait en même temps.
- CorrigéSuivre depuis une autre page un lien vers une section de la page d'accueil menait à un écran blanc. Le script d'interaction n'était pas rebranché après une navigation côté client, ce qui laissait aussi inertes l'accordéon, les compteurs et la démonstration en direct.
- CorrigéLe seul chiffre en direct de la page d'accueil était formaté selon la locale du serveur et non celle du lecteur. Le français affiche désormais 4 182 et le portugais du Brésil 4.182, en accord avec les chiffres fixes qui les entourent.
- CorrigéDeux liens de navigation pointaient vers des routes qui n'existaient pas, et le lien du pied de page vers le blog envoyait un lecteur français vers l'index anglais.
Les comptes, un expéditeur vérifié, et la phase de soumission
- AjoutéLa connexion par un code à six chiffres reçu par e-mail, ou avec Google. Il n'y a nulle part dans la base de données de colonne mot de passe, et une colonne qui n'existe pas ne peut pas fuiter.
- AjoutéRien ne part sous une adresse dont un compte client n'a pas prouvé la propriété. L'envoi est conditionné à un enregistrement DNS publié sous le domaine. Un lien de confirmation prouve le contrôle d'une boîte aux lettres, et un fichier sur un serveur web prouve le contrôle d'un serveur web ; ni l'un ni l'autre n'est l'affirmation en question. Les adresses de messagerie gratuites sont refusées d'emblée, avec leur propre message.
- AjoutéLa phase de soumission. Un message approuvé est préparé, répété contre le vrai formulaire, et seulement ensuite envoyé. Il devient un envoi effectué quand le formulaire l'accepte, et pas avant. La répétition est le comportement par défaut, un formulaire derrière un CAPTCHA est refusé et non résolu, et aucun chemin de code ne relance une requête qui est peut-être déjà partie : il n'existe aucune condition réseau sous laquelle une deuxième lettre à un inconnu serait la bonne réparation.
- AjoutéDeux sources de découverte. Un annuaire d'entreprises de données, dont la condition d'entrée est précisément le profil que nous cherchons : 28 domaines sur 28 issus du premier balayage ont résolu, contre environ quatre sur cinq pour les biographies. Et l'annuaire Y Combinator, la seule source qui dise ouvertement si une entreprise est encore en activité. 1 861 de ses 6 108 entreprises sont déjà rachetées ou inactives.
- AjoutéUn compte client peut nommer les entreprises auxquelles il vend déjà, et exclure celles qu'il ne veut pas voir contactées. Les deux listes étaient vides depuis l'écriture de la règle qui les lit, ce qui explique qu'un de ses douze plus gros clients actuels ait été étudié comme un prospect froid.
- AjoutéUn profil d'expéditeur, pour qu'un formulaire demandant un numéro de téléphone ou un pays ait où le trouver. Rien sur cette page n'est déduit. Un numéro de téléphone saisi dans le formulaire de contact d'un inconnu est une affirmation au sujet d'une entreprise réelle : il vient donc d'une personne, ou il ne part pas.
- ModifiéLe tableau de bord affiche le vrai journal. Il rendait jusque-là un jeu de données écrit avant l'existence du pipeline : plus animé que la réalité, et chacun de ses chiffres inventé.
- ModifiéToutes les entreprises qualifiées obtenaient exactement 20. Trois des quatre termes du score ne pouvaient pas varier au moment du calcul : la file n'était donc que l'ordre d'insertion déguisé en note. Le score compte désormais six termes, tous connaissables au moment où il est pris.
- CorrigéLe formulaire de connexion pouvait rester bloqué indéfiniment sur « Checking ». Le serveur répondait pourtant tout du long ; une connexion coupée laissait le bouton figé, sans message et sans autre issue qu'un rechargement.
- RetiréTailwind, et quatre composants orphelins. Plus rien dans l'application n'utilisait de classe utilitaire.
L'Index des Refus cesse d'être illustratif
- ModifiéL'Index des Refus lit le journal. Sous un titre annonçant que nous publions nos refus se trouvait un tableau de pourcentages inventés, légendé « Répartition donnée à titre d'illustration ». C'était la seule partie de la page qui plaidait contre elle-même. La première lecture réelle a donné 72 refus sur 151 entreprises, chacun accompagné de la phrase écrite au moment du verdict.
- AjoutéL'enrichissement, la rédaction et une file de revue. Un verdict tiré du site de l'entreprise elle-même l'emporte sur celui tiré de sa biographie : 79 validations provisoires sont devenues 5, avec parmi les victimes 16 domaines morts et 6 homonymies. Une validation renversée est réécrite en refus, si bien que l'Index des Refus devient plus honnête à mesure que le pipeline tourne, au lieu de s'en éloigner.
- AjoutéLes e-mails de connexion partent sous un plafond que nous nous imposons de 40 envois par heure, réservé avant l'envoi plutôt que compté après. La façon réaliste de perdre une boîte aux lettres n'est pas un usage légitime et régulier, c'est une boucle de relance à 3 h du matin.
- CorrigéDeux points d'accès en lecture répondaient à des appelants anonymes et renvoyaient jusqu'à 500 lignes du journal pour le compte client que nommait l'URL. Les deux sont désormais derrière la porte du tableau de bord, et le compte client vient de la session plutôt que de la chaîne de requête.
- CorrigéLa démonstration répondait de mémoire sur les entreprises connues au lieu d'aller regarder. Un domaine est revenu complet avec zéro recherche et zéro requête, alors que la page juste à côté affirme que la démonstration va réellement voir. Les deux invites portent désormais un plancher, et le texte sur la durée a été corrigé avec elles : « environ 40 secondes » est devenu une minute ou deux, ce qu'elle fait réellement.
- ModifiéLa démonstration tourne sur un modèle épinglé, à un niveau d'effort choisi, plutôt qu'en héritant de ce que l'outil livre par défaut. À l'effort par défaut, une exécution a passé 203 secondes, épuisé son budget de tours et n'a rien renvoyé, pour près de trois fois le coût de celle qui a abouti en 73.
- AjoutéLes échecs de la démonstration sont distingués. Un quota épuisé, un modèle surchargé, un dépassement de délai et un exécuteur non configuré se réduisaient auparavant à un seul message, qui se lisait comme si le visiteur avait saisi un mauvais domaine.
- AjoutéLes limites de débit, les budgets d'exécution et le disjoncteur survivent à un déploiement. Ils vivaient en mémoire : livrer un changement distribuait donc un quota tout neuf et oubliait chaque exécution déjà en cours.
- AjoutéLes exécutions de la démonstration sont consignées, pour que les affirmations de cette page puissent être vérifiées contre ce qu'elle a réellement fait. L'adresse du visiteur est hachée avec un sel et jamais conservée : rien ici n'a besoin d'identifier qui que ce soit, seulement de compter.
Premier commit, et les refus deviennent des traces
- AjoutéKnockwire, rebaptisé depuis delvebase le jour de son démarrage. Le produit n'est pas la liste qu'il produit. C'est la liste qu'il refuse, et le motif attaché à chaque refus.
- AjoutéLe journal des lectures. Chaque entreprise regardée est conservée, qualifiée ou non, avec son issue, son motif de refus et un lien de preuve qu'une personne peut ouvrir. Supprimer une entreprise refusée détruirait les preuves sur lesquelles ce produit repose : rien n'est donc supprimé.
- AjoutéLa découverte. Cinq façons de trouver des entreprises ont été mesurées contre des points d'accès réels et une l'a emporté : lire ce que les organisations écrivent sur elles-mêmes a renvoyé 1 171 organisations avec un site web à partir de 136 requêtes, dont 186 se sont qualifiées. Publier un scraper est un comportement de fournisseur. Écrire « plateforme d'intelligence tarifaire » dans sa propre biographie est un comportement d'acheteur, et toute la première étape repose sur la capacité à les distinguer.
- ModifiéLe filtrage des fournisseurs est sorti de la découverte pour entrer dans l'étape de jugement. Les concurrents étaient écartés en silence : ils n'atteignaient donc jamais le journal, et un refus que personne ne peut auditer n'est pas une preuve.
- CorrigéUn concurrent a atteint la liste des qualifiées lors de la première exécution réelle. La liste d'exclusion des fournisseurs comptait dix noms et il en fallait trente. C'est le pire échec qu'ait connu ce produit, et il est consigné ici plutôt que réparé en silence.
- AjoutéLa résolution du contact, qui ne devine jamais. Un formulaire de contact publié est préféré à une adresse, parce qu'un formulaire est une porte que l'entreprise a ouverte pour cet usage. Une adresse de fonction n'est utilisée que si l'entreprise la publie réellement. Il n'y a aucune permutation prenom.nom et aucune déduction de motif, et robots.txt est lu avant toute requête.
- AjoutéLe site, les tarifs, ainsi que les conditions, la confidentialité et la politique de remboursement.
- AjoutéLa démonstration en direct du site public, qui tourne sur le domaine que le visiteur saisit, quel qu'il soit. Elle est enfermée plutôt que crue sur parole : deux outils autorisés et tout le reste refusé, un répertoire de travail vide, aucun accès à notre environnement, et les pages récupérées traitées comme des données et non comme des instructions.
- CorrigéTrois façons d'abuser de cette démonstration, toutes démontrées en production plutôt que supposées. Deux de ses trois actions n'étaient pas comptabilisées, la limite par visiteur pouvait être contournée avec un seul en-tête, et rien ne plafonnait le nombre d'exécutions simultanées.
- AjoutéLe journal est passé en production sur une vraie base de données le soir même. Première passe : 60 entreprises lues, 36 qualifiées, 24 refusées, chaque refus portant son motif et son lien de preuve.