Für dreißig Versionen sagte die Bestätigung in unserem Kameraobjektiv Folgendes, in welcher Sprache du auch immer verwendet hast: „Es verschwindet für alle aus der Welt, und das kann nicht rückgängig gemacht werden.“ Ein Tropfen ist ein virtuelles Objekt, das jeder Nutzer an einem realen Ort für einen Fremden hinterlassen kann, damit er ihn findet. Was der Button tat, war, ihn von einer Liste auf deinem eigenen Telefon zu entfernen. Der Tropfen blieb genau dort, wo er war – auf jedem anderen Telefon – für immer.

Niemand hat die Lüge bemerkt, und der Grund ist der Punkt. Das Objektiv verbirgt deine eigenen Tropfen vor deinem eigenen Radar, weil du bereits weißt, wo du sie abgelegt hast. Also zeigte der Bildschirm sofort nichts an an der Stelle, an der der Tropfen gewesen war, sobald die lokale Kopie weg war – und es sah für die einzige Person korrekt aus, die jemals nachschauen würde. So überlebt eine Lüge dreißig Releases: nicht durch Verbergen, sondern indem sie aus jedem Blickwinkel, den ein Nutzer einnehmen kann, von der Wahrheit nicht zu unterscheiden ist.

Die Korrektur hat eine zweite Hälfte. Geschrieben, überprüft, getestet, bei jeder Prüfung grün. Dann eine konfrontative Überprüfung, bei der Leser versuchen, die Arbeit zu zerbrechen statt sie zu genehmigen, fand, dass der neue „Löschen“-Button eine Adresse aufruft, die nicht existierte. Das Lens ist eine Webseite, und das Backend sitzt auf einer anderen Domain, also gehen alle Aktionen über eine kleine Weiterleitungsroute auf der eigenen Seite der Lens. Drei existierten: platzieren, beanspruchen, bewegen. Der vierte, löschen, war nie erstellt worden. Jeder Test bestand, weil die Tests das Netzwerk durch einen Platzhalter ersetzen und prüfen, dass die richtige Adresse angefragt wird. Sie belegen, dass der Client die richtige Frage stellt und nichts darüber, ob irgendetwas überhaupt antwortet. Ausliefern wäre eine Regression gewesen: Der alte Button hat zumindest deinen eigenen Beutel geleert, und der neue hätte einen Fehler dauerhaft angezeigt.

Jetzt der Teil, den dieser Raum wiedererkennt. Jedes Item, das ein Unternehmen jemandem in bonuz übergeben kann: ein Gutschein, eine Mitgliedschaft, eine Stempelkarte, eine Pass—wird aus einem einzigen Engagement-Vertrag auf Base geprägt. Es gibt jetzt zwei: einen älteren und seinen verbesserten Nachfolger. Der alte wird nie aus der Anzeige entfernt, weil das Entfernen Dinge löschen würde, die Menschen bereits besitzen. Der Gründer stellte die Regel laut auf: „Der alte wird irgendwann zum Prägen in den Ruhestand geschickt, aber er wird nie ausgestellt oder zur Anzeige abgeschaltet.“ Dann bat er um etwas, das niemand abgedeckt hatte: „Der neue Smart Contract ist nur eine Verbesserung. Prüft nochmal, ob ihr es richtig gemacht habt, vergleicht mit dem alten.“

Die Schnittstellen passten fast exakt. Die Daten nicht. Eine Stempelkarte speichert, wie viele Stempel man hat und wie viele man braucht. Im alten Vertrag wird der zweite Wert unter dem Namen max punches mit einem Leerzeichen gespeichert. Im neuen heißt er max_punches mit einem Unterstrich. Die App liest nur den Unterstrich. Also meldete jede Stempelkarte im alten Vertrag, dass sie null Stempel braucht: keine Fortschrittsanzeige, kein Zähler, der „3 von 10“ liest, und weil die Abschlussprüfung ein Maximum über null voraussetzt, konnte eine fertiggestellte Karte nie als fertig erkannt werden. Jemand konnte seine Karte füllen und wurde nie mit der Belohnung bedacht.

Kein Interface-Vergleich hätte das gezeigt. Kein Type-Checker, keine Test-Suite, kein Schema. Sichtbar war es nur, indem man echte Items von der Live-Chain las und die beiden nebeneinanderlegte. Wenn zwei Dinge beide unterstützt werden müssen, muss das Zerbrechen von einem davon scheitern. Den neuen Contract aus einer Liste zu entfernen ist der naheliegende Test. Den alten zu entfernen ist der Test, den die Leute vergessen—und der, der das Versprechen schützt.

Die gleiche Bevorzugung sitzt vorne an der Tür. LIFE-Modus ist gesperrt, und ein Wallet öffnet ihn, indem es einen Life Key hält—ein Item, dessen On-Chain-Attribute sagen, was es gewährt. Das Tor liest die Chain und nichts sonst. Es hält keine Liste genehmigter Wallets, weil eine Liste etwas ist, das eine Person pflegen muss, und eine Chain ist nicht das, was jemand verwaltet.

Zwei Zäune wurden gebaut, bevor sie gebraucht wurden. Nutzer können in beliebigen rollierenden 24 Stunden zehn Drops platzieren: „Darum begrenzen wir Nutzer jetzt auf zehn Drops pro Tag, damit es nicht missbraucht werden kann.“ Die Grenze kam zuerst, bevor die soziale Funktion kam, die sie schützt. Drops können außerdem anonym gemeldet werden, weil die Anforderung eines Accounts, um etwas Anstößiges zu melden, dazu führt, dass der Großteil davon gar nicht gemeldet wird. Aber anonyme Meldungen können niemals irgendetwas verdecken—bei jeder Menge. Nur eindeutig identifizierte Accounts zählen zur Schwelle: ein Account, der denselben Drop wiederholt meldet, zählt nur einmal, und Verstecken ist immer rückgängig zu machen. Eine Moderationsfunktion, die anonyme Menge auslösen kann, ist ein „Takedown“-Werkzeug, das gegen den gerichtet ist, den jemand nicht leiden kann.

Dann unser eigener Ausfall. Eine Änderung fügte der Datenbank einen neuen Datensatztyp hinzu. Das System, das Datensätze speichert, hält eine Tabelle mit Bearbeitungssperren mit einer Spalte pro Datensatztyp und baut eine einzige Abfrage, die alle Spalten auf einmal benennt. Der neue Typ ging in die Konfiguration, aber nicht in diese Tabelle—also nannte die Abfrage eine Spalte, die es nicht gab. Damit schlugen alle Schreibvorgänge in der Datenbank fehl. Jeder Schreibvorgang, jeder Art, einschließlich der eigenen Speichertaste des Admin-Panels. Siebenundfünfzig Minuten, selbst verursacht und selbst gemeldet. Typen durchgekommen, Testsuite durchgekommen, und die Prüfung, die es gibt, um Datenbankänderungen zu üben, bestand auch—weil sie die Änderung auf eine leere Datenbank anwendet, in der die fehlende Spalte gleichermaßen fehlt. Eine grüne Übung bedeutet: Die Änderung lässt sich anwenden. Es bedeutet nicht, dass das Ergebnis vollständig ist.

Jenseits der Chain liegen die Fehler, die kein Monitoring sehen kann. Ein Kachel-Dienst für Karten wechselte hinter einen Key und lieferte, statt abzulehnen, ein gültiges Bild mit der diagonal gedruckten Meldung „API KEY REQUIRED“ aus: Status zweihundert, korrekter Dateityp, vernünftige Größe, jede Prüfung grün. Achtundzwanzig Veranstaltungsfotos stellten sich als generiert heraus statt aufgenommen—alle erzeugt, indem man den Namen der Location in ein Bildmodell fütterte. So wurde Wild Wadi Waterpark, ein Wasserpark in Dubai, mit einem Wüstental illustriert. Alle achtundzwanzig sind heute aus der Produktion verschwunden. „Ihr habt wirklich total kaputte Bilder genommen. Das ist etwas in Arizona, das gibt’s nicht.“

Der ehrliche Zustand. Die Lens ist live, sie läuft jetzt in vierundzwanzig Sprachen, Drops können nun tatsächlich gelöscht werden, und Loyalty Cards auf beiden Contracts werden richtig angezeigt und vollständig abgeschlossen. Ungefähr hundertundsiebzig Fotos warten immer noch auf die Zuordnung. Etwa ein Drittel der Bildbibliothek liegt unter der Größe, die die App bevorzugt, und eine erneute Verarbeitung kann das nicht beheben, weil das System Bilder nicht vergrößert. Einige der ältesten Stempelkarten wurden ohne das Stempelziel geprägt, und kein Client-Code erreicht diese. Und die App wurde seit dem Eintrudeln eines beträchtlichen Teils dieser Arbeit nicht neu gebaut—also existieren mehrere der hier beschriebenen Fixes zwar im Repository, aber noch nicht auf irgendeinem Telefon.

Jeder Person, der diese Ausfälle geschadet hätten, war es nicht möglich, sie zu melden. Die Person, deren Stempelkarte nicht abgeschlossen wurde, geht davon aus, dass sie sich beim Zählen vertan hat.

„Updates werden sehr ernst genommen. Wir müssen vorsichtig sein. Weniger ausliefern, aber nur perfekte.“