Unseren schönsten Screen gelöscht
Etwa ein Jahr lang hatte Classifyre ein Feature namens Fingerprints. Es war der Screen, auf den man in Demos zeigte: ein force-gerichteter Graph über den gesamten Bestand, Assets als Knoten, Ähnlichkeitslinks dazwischen, Cluster, die dort leuchteten, wo derselbe Kunde in vier Systemen auftauchte. An einem Slider ziehen, und der Graph lichtete sich oder verdichtete sich. Es sah aus wie Intelligenz.
Wir haben ihn entfernt. Was ihn ersetzt hat, ist eine Liste.
Dies ist die Geschichte, warum — und was sie verändert hat, inklusive des Teils, den wir nicht erwartet hatten: was nämlich mit Fällen passierte.
Was Fingerprints wirklich taten
Die Idee dahinter war solide, und wir haben alles davon behalten.
Jeder Befund, den ein Detektor meldet, trägt einen Wert: eine E-Mail-Adresse, eine IBAN, eine nationale ID, einen Personennamen. Normalisiert man diese Werte, hasht sie, dann kann man über einen ganzen Bestand eine billige Frage stellen — welche Assets enthalten dieselben Werte? Gewichtet man die Antwort so, dass eine geteilte Kreditkarte mehr zählt als ein geteilter Ländercode, bekommt man einen Score: den Anteil der Beweise zweier Assets, der wirklich matcht.
Diese Maschinerie funktioniert. Sie ist deterministisch, sie ist erklärbar, und für jeden Link, den sie produziert, kann man auf die exakten Werte zeigen, die dafür verantwortlich sind. Wir wollten sie nie ersetzen.
Das Problem war nie das Matching. Es war der Screen, den wir daraufgesetzt hatten.
Das Canvas-Problem
Ein Ähnlichkeits-Canvas
412 Paare. Keine Ordnung, keine Zählungen, kein Ende. Jede Sitzung startete bei null.
Eine gereihte Queue
Dieselben 412 Paare. Eine Regel räumt 146 davon ab; 17 brauchen überhaupt kein Urteil.
So haben wir es, immer wieder, auf echten Korpora ablaufen sehen.
Ein Canvas ist ein Ziel, kein Schritt in einer Aufgabe. Es hat keinen Abschlusszustand. Ein Reviewer, der den Fingerprint-Graphen am Dienstag öffnete, konnte nicht wissen, was er am Montag angesehen hatte, wie viel noch übrig war oder ob er vorankam. Also sah er es sich an, sagte „huh, interessant“ und schloss es. Niemand arbeitete einen Backlog durch einen force-gerichteten Graphen ab, denn ein force-gerichteter Graph hat keinen Backlog. Er hat eine Form.
Er kannte kein Was-zählt, also holte er alles. Auf einem Korpus von 61.000 Assets war der Graph 61.000 Knoten und 272.000 Kanten — über zwei Gigabyte lebende JavaScript-Objekte. Er erschöpfte den API-Heap allein, einmal pro Batch angefasster Assets während eines laufenden Scans. Der Screen, der Ihnen Ihre Daten zeigen sollte, war der Grund, warum der Prozess, der Ihre Daten hielt, ständig starb. Wir haben damals über einiges davon geschrieben; der Fix kam immer auf dieselbe Ursache zurück. Ein Canvas hat keinen Grund, nach weniger zu fragen, denn er kann Ihnen nicht sagen, was weniger bedeuten würde.
Der Ähnlichkeits-Slider war eine Lüge über die Arbeit. Ihn zu ziehen änderte, welche Links gezeichnet wurden. Es änderte nicht, welche Entscheidungen noch zu treffen waren, denn es gab keine Entscheidungen — nichts auf dem Screen hielt ein Urteil fest. Jede Sitzung startete bei null. Man konnte dasselbe falsche Cluster montags, mittwochs und freitags anstarren, und das Produkt würde es nie erfahren.
Und es behandelte jedes Duplikat als gleich interessant. Eine Staging-Tabelle, die der Produktionstabelle ähnelt, aus der sie gebaut wurde, ist kein Befund. Es ist eine Pipeline, die ihren Job tut. Wenn Ihr Duplikat-Tool solche neben echten Problemen meldet, im selben visuellen Gewicht, lernen Menschen, das Tool zu ignorieren. Das ist, denken wir, der eine Hauptgrund, warum metadatenbasierte Duplikaterkennung einen schlechten Ruf hat.
Womit wir es ersetzt haben
Das neue Feature heißt Duplikatprüfung, und es ist eine Queue mit drei Ebenen. Jede Ebene beantwortet eine Frage und endet in einer Aktion.
Jeder Match wird unter dem Grund abgelegt, aus dem er matchte: der Menge an Wert-Labels, die beide Assets gemeinsam hatten. 18.000 Paare stellen sich als fünf oder sechs Muster heraus.
Ein Muster sagt, was für eine Entscheidung es ist: ein Cutoff, eine Ausschlussregel, ein No-op oder echtes Urteil pro Paar. Dann zeigt es exakt, wie viel von Ihrem Backlog sein Abarbeiten entfernt.
Ein Paar, die Werte hinter dem Match, die Gegenbeweise und fünf Tasten. Entscheiden rückt zum nächsten vor.
Die drei Ideen, die es abschließbar machen, sind einfach genug, um jede in einem Satz zu sagen.
1. Nach Ursache gruppieren, nicht nach Paar
Ein Paar ist ein Symptom. Die Ursache ist, warum es matchte. Legt man Matches unter ihrer Ursache ab, ist die oberste Zeile auf einem echten Korpus fast immer etwas mit einem Einzeilen-Fix: ein Platzhalter, den Ihr ETL in leere Felder schreibt, eine Support-Adresse in jedem Ticket-Footer, ein Boilerplate-Geheimhaltungshinweis auf vierhundert Verträgen.
Das zu finden kostete vorher zehn Minuten Slider-Ziehen. Jetzt ist es Zeile eins.
2. Sagen, was eine Entscheidung wert ist
Jedes Muster trägt eine Zahl, die wir Nachher / Vorher nennen: wie viele unentschiedene Paare über Ihren ganzen Workspace vor dieser Aktion übrig sind und danach. Ein Muster, das 8.400 Paare von einem Backlog von 12.000 nimmt, ist zuerst zu tun, was sonst noch auf dem Screen steht.
Muster sind nach dieser Hebelwirkung geordnet, nicht nach Größe. Nach Größe zu ordnen spült unbehebbares Rauschen nach oben; nach Score zu ordnen vergräbt die leichten Siege unten. Nach wie viel eine Entscheidung erledigt zu ordnen legt die Nachmittagsarbeit in die ersten drei Zeilen.
3. Erwartete Duplikate von überraschenden trennen
Das ist die Änderung, auf die wir am stolzesten sind, und sie brauchte ein zweites, unabhängiges Signal.
Duplikat-Matching liest die Inhalte Ihrer Assets. Lineage liest etwas völlig anderes: Konnektor-Kataloge, View-SQL, Query-Logs, dbt-Manifeste. Weil beide keine Source teilen, fügt ihr Kombinieren echte Information hinzu:
| Zwei Assets sehen nahezu identisch aus, und … | Das heißt | Priorität |
|---|---|---|
| es gibt einen Lineage-Pfad zwischen ihnen | Eine abgeleitete Kopie. Ein Mart, der seiner Source ähnelt. | Niedrig — erwartet |
| es gibt keinen Pfad, und beide Seiten haben Lineage | Zwei Teams haben unabhängig dasselbe gebaut | Hoch |
| wir haben für eine Seite keine Lineage | Eine Abdeckungslücke, kein Beweis | Nach den Werten urteilen |
Diese mittlere Zeile ist der Grund, überhaupt ein Duplikat-Tool zu haben. Sie ist teuer — zwei Pipelines, zwei Sätze Wartung, zwei Chancen, still zu divergieren — und sie ist unsichtbar, denn kein Team hat Grund zu schauen. Niemand reicht ein Ticket zu etwas ein, von dem es nicht weiß, dass es existiert.
In der App bekommt diese Zeile die Alarmfarbe und einen Satz Copy:
Zwei Teams scheinen unabhängig dasselbe gebaut zu haben. Das ist der Fall, dem es nachzugehen lohnt.
Hier gibt es ein Implementierungsdetail, das wir nennen wollen, weil es die Sorte Fehler ist, die das ganze Feature still wertlos gemacht hätte. Classifyres eigene Ähnlichkeitslinks liegen im selben Beziehungsgraphen wie Lineage. Würde der Test „gibt es einen Pfad zwischen diesen beiden Assets?“ durch jene laufen, fände jedes Paar in der Queue einen Pfad — zu sich selbst. Alles meldete sich als erklärt, nichts eskalierte je, und der Check sähe aus, als arbeitete er perfekt. Also sind Beziehungen, die die Duplikat-Engine produziert, namentlich ausgeschlossen. Ein Check ist nur laufenswert, wenn etwas anderes als das Geprüfte antworten kann.
Near-Duplicate, nicht nur Duplikat
Die andere Hälfte des Rewrites steckt im Namen. „Fingerprints“ implizierte exakte Identität: gleiche Werte, selbe Sache. Echte Bestände sind unordentlicher.
Vier verschiedene Dinge können zwei Assets zur selben Sache machen, und wir halten sie jetzt auseinander, statt sie in eine Zahl zu mitteln:
| Familie | Matcht auf | Fängt |
|---|---|---|
| Geteilte Werte | Die konkreten Werte in Befunden | Denselben Kunden in drei Systemen |
| Ähnliche Schreibweise | Phonetische Codes auf namensartige Werte | Jon Smyth und John Smith |
| Identischer Inhalt | Dieselben Bytes | Eine Datei, kopiert zwischen Buckets |
| Wiederholter Text | Bedeutung, via Embeddings | Denselben Absatz, umformuliert |
Diese letzte ist wirklich neu, und hier verdient „Near-Duplicate“ das Wort. Sie kommt aus der semantischen Schicht statt aus Wert-Überlappung: Zwei Passagen, deren Embeddings nah beieinander sitzen, sagen dasselbe, auch wenn sie gar keine wörtlichen Werte teilen.
Wir hielten die Familien aus einem Grund getrennt, dessen Lernen dauerte: Sie scheitern verschieden, und zwei Maße zu mitteln, die verschieden scheitern, gibt eine Zahl, die in beide Richtungen falsch und unmöglich zu debuggen ist. Getrennt bekommt jede Familie ihren eigenen Fix — Wert-Überlappung wird mit Gewichten und Ausschlüssen getunt; wiederholter Text wird durch Ausschluss des Boilerplates gefixt. Vermischt wäre kein Fix auffindbar.
Wie eine Entscheidung jetzt aussieht
0.71
die Balken unten summieren sich auf 0.71
DE89 3704 …
a.mendes@…
ana mendes
nothing shared
nothing shared
Links der Linie stehen Beweise dagegen: Adresse und Telefon auf einem Asset, die das andere nicht hat. Sie stecken in der Summe, nicht außerhalb.
Der Paar-Screen schuldete dem Reviewer drei Dinge, die der Canvas ihm nie gab.
Eine Zahl, die man nachprüfen kann. Das Match-Gewicht ist der Anteil der verfügbaren gewichteten Beweise beider Assets, der wirklich matchte. Der Breakdown darunter ist ein Balken pro Label, und die Balken summieren sich auf die Zahl über ihnen. Nichts ist in einem Blend versteckt. Würden sie je nicht aufgehen, wäre das der eine unverzeihliche Bug auf dem Screen — die Arithmetik ist also so gebaut, dass es unmöglich ist.
Gegenbeweise, in denselben Einheiten wie Beweise dafür. Ein Label, das nur auf einem der beiden Assets steht, produziert einen positiven Balken für das, was es hätte beitragen können, und einen gleich großen negativen für das, was es nicht tat. Das ist die ehrliche Art, Dissens zu zeigen: als Gewicht, das da war und ungeclaimt blieb. Die meisten Ähnlichkeits-Tools lassen es schlicht weg — so kommt man zu einem selbstbewussten 0,8 zwischen zwei Datensätzen, die einen Namen teilen und sich in allem anderen widersprechen.
Vier Urteile, nicht zwei. Bestätigen und Kein Duplikat sind die offensichtlichen. Cluster hier trennen ist eine Aussage über die Form des Clusters statt über das Paar — der Fix für das klassische falsche Cluster, wo A zu B matcht, B zu C matcht und A mit C nichts zu tun hat. Und Unsicher ist ein erstklassiger Button, kein Ausweg: Ein Binärurteil auf ein wirklich mehrdeutiges Paar zu zwingen produziert schlechte Datensätze, und ein Stapel „unsicher“ ist selbst das Signal, dass Ihr Review-Band sitzt, wo die Beweise nicht trennen.
Dann rückt die Queue vor. Drücken Sie c und Sie sind beim nächsten Paar, unter denselben Cutoffs und denselben Filtern, mit sichtbarer Zählung des Rests. Klingt klein. Es ist der Unterschied zwischen einer Queue und einem Formular.
Der Teil, den wir nicht erwartet hatten: was es mit Fällen tat
Wir bauten diesen Screen um, um Duplikatprüfung abschließbar zu machen. Der größere Effekt lag downstream.
Unter Fingerprints war, einen Cluster in einen Fall zu heben, ein Klick — und fast niemand nutzte ihn. Rückblickend ist der Grund offensichtlich: Ein Cluster ist kein Beweis. Er ist die Meinung einer Maschine, und ihn in einen Fall zu ziehen hieß, eine ungeprüfte Behauptung in eine Akte zu importieren, die halten soll, was jemand geprüft hat. Die Fälle, die so starteten, waren schwächer dafür — ein Ermittler, der einen öffnete, fand einen Stapel Assets und keine Aufzeichnung, warum jemand meinte, sie gehörten zusammen.
Ein bestätigtes Duplikat ist anders in der Art. Jemand sah sich zwei Assets an, sah die Werte hinter dem Match, sah die Gegenbeweise und sagte ja. Das ist ein Beweis, mit Provenienz und Zeitstempel.
Drei konkrete Änderungen folgten daraus, das ernst zu nehmen.
Entscheidungen überleben die Queue. Eine Queue allein ist Write-only — man beurteilt ein Paar und es verschwindet, was das Urteil fünf Minuten später wertlos macht. Also gibt es jetzt ein Entscheidungs-Ledger: was beurteilt wurde, von wem, gegen welchen Score und was daraus wurde. Sein nützlichster Filter ist „ging noch nirgendwohin“: als echt bestätigte Duplikate, nie in einen Fall genommen. Diese Liste ist der billigst mögliche Ermittlungsstart, denn jeder Eintrag ist bereits von einem Menschen verifiziert.
Ein Urteil weiß, wann es alt wurde. Urteile speichern den Score, gegen den sie gefällt wurden. Scoren Sie den Korpus neu — neue Gewichte, ein neuer Ausschluss, frische Befunde — und jedes Paar, dessen Score sich materiell bewegt hat, wird als neu gescort seit Ihrer Entscheidung geflaggt. Das Urteil wird nicht weggeworfen, denn das würfe echte Arbeit weg. Es wird auch nicht als aktuell präsentiert, denn es wurde über eine andere Zahl gefällt.
Fälle und Duplikate zeigen endlich aufeinander. Eine aus einem Paar eröffnete Anfrage erbt die echte Match-Signatur: die Labels, die matchten, gescopet auf die Quellen, aus denen sie kamen. Sie beobachtet dasselbe, statt mit leerem Formular zu starten. Und die Agenten, die Ihre Fälle bearbeiten, sehen menschliche Urteile — also hebt ein Agent nie ein Paar erneut hoch, das jemand bereits entschied, und argumentiert nie gegen eine Entscheidung, die er nicht sehen kann.
Wo die Agenten hinpassen
Wir hatten eine stehende Regel, die wir während dieses Rewrites anzogen: Ein Agent darf die langweiligen Fälle abräumen und sonst nichts.
Das Matching selbst hat kein Sprachmodell darin. Es ist deterministisch — normalisieren, hashen, scoren, clustern — und es läuft nach jedem Scan, vor dem Autopilot-Zyklus, damit Agenten nie über alte Duplikate räsonieren.
Dahinter gibt es exakt eine Situation, in der ein Agent selbst ein Urteil vermerkt: ein Match-Gewicht bei oder über 0,95 und ein Lineage-Pfad, der es erklärt. Diese Kombination ist eine abgeleitete Kopie, wo eine menschliche Entscheidung nichts hinzufügt. Beide Bedingungen sind nötig, und die zweite ist die interessante — ein nahezu perfekter Score ohne Erklärung ist das eine Wertvollste, das dieses Produkt hochheben kann, und genau das sollte ein Mensch sehen.
Jede Agenten-Entscheidung wird gestempelt und getrennt von Menschenarbeit gezählt. Ein Agent, der Ihre Queue still leerte, hätte die eine Zahl zerstört, über die zu berichten der Screen existiert.
Was wir lernten
Ein Screen, der nicht fertig werden kann, wird nicht benutzt. Nicht „weniger benutzt“ — nicht benutzt. Menschen sind gut darin, Arbeit ohne Ende zu erkennen und abzulehnen, sie zu beginnen. Hat Ihr Feature keinen Abschlusszustand, hilft kein Polish daran.
Nach Ursache zu gruppieren ist mehr wert als jedes Ranking. Wir steckten echte Arbeit in gutes Ranken von Paaren. Es zählte weit weniger, als sie unter dem abzulegen, warum sie matchten — denn das zweite offenbart gelegentlich, dass vierhundert Paare eine behebbare Ursache teilen, und kein Ranking von vierhundert einzelnen Paaren sagt Ihnen das je.
Zwei unabhängige Signale schlagen ein gutes. Lineage ist kein besseres Ähnlichkeitsmaß als Wert-Überlappung. Es ist eine andere Frage, beantwortet aus einer anderen Source, und genau darum produziert das Kreuzen der beiden den Befund, den zu haben sich lohnt. Zwei lexikalische Maße zu stapeln hätte fast nichts produziert, denn sie stimmen meist überein.
Erklärbarkeit muss Arithmetik sein, keine Erzählung. „Diese matchten, weil sie eine E-Mail und einen Namen teilen“ ist Erzählung. Balken, die sich auf die Zahl über ihnen summieren, mit dem Dissens im selben Maßstab wie der Konsens, ist Arithmetik. Nur eines davon überlebt, wenn jemand nachprüft.
Der Canvas war wirklich der schönste Screen, den wir je auslieferten. Er ist nicht mehr im Produkt, und die Zahlen, die er zeichnete, hängen jetzt an Entscheidungen, die jemand traf. Dieser Tausch lohnte.
Wer die Details will: Die Dokumentation deckt jeden Screen und jede Aktion ab. Es gibt auch eine Seite, die nichts tut, als die Zahlen eine nach der anderen zu erklären, weil wir es leid wurden, dieselben Fragen zu beantworten.