rwa

Eine Rewritable-Datei sollte wissen, was sie ist

Rewritable begann mit einer einzigen Idee zum Bearbeiten, und es war eine gute. Sie öffnen eine eigenständige HTML-Datei, beschreiben in einem Satz die gewünschte Änderung, und ein Modell schreibt den Quelltext des Dokuments an Ort und Stelle neu. Diese Oberfläche nannten wir die Linse: ein einziges Verb, modify, gerichtet auf das, was die Datei gerade ist. Die Linse ist schon von ihrer Konstruktion her typunabhängig, denn unter ihr ist jeder Container nur Text, der neu geschrieben wird, und im Neuschreiben von Text sind Modelle sehr gut. Eine Runtime, ein Bearbeitungsvertrag, beliebiger Inhalt. Das war das ganze Versprechen. Wie sich herausstellte, war es auch der verräterische Hinweis.

Richten Sie die Linse auf eine Tabellenkalkulation, und es fühlt sich nicht mehr natürlich an. Eine Tabellenkalkulation ist keine Prosa. Ihr Wesen sind direkte Manipulation und das Weitergeben von Änderungen: Sie tippen einen Wert in eine Zelle, eine abhängige Zelle rechnet neu, und die Schleife ist eng, lokal und unmittelbar. „Änderung beschreiben und auf die vollständige Neufassung warten“ verfehlt diese Interaktion um eine Größenordnung. Der naheliegende Flicken ist ein Sonderfall: ein Datatable-Harness neben der Linse. Aber das zersplittert die eine Eigenschaft, auf die es ankommt (eine portable Datei, eine Runtime, ein Erweiterungsmodell), und bringt uns zurück auf den Weg zu Office, wo sich jeder Typ seine eigene Anwendung verdient. Die eigentliche Frage ist, wie wir typspezifische Reichhaltigkeit ohne fragmentierte Runtime bekommen.

Die Linse war die Affordanz für Prosa

Die Lösung beginnt damit, zu benennen, was die Linse wirklich ist. Sie ist nicht die Grundeinheit des Bearbeitens. Sie ist die Affordanz für Prosa, das Bearbeitungsverhalten, das zu Dokumenten aus Text passt, und sie wirkte nur deshalb universell, weil Prosa der erste Typ war, den wir gebaut haben. Bearbeiten war nie ein einziges Verb. Es ist typabhängig: Was Bearbeiten bedeutet, ergibt sich daraus, was das Ding ist. Ein Dokument will chirurgische Neufassungen einzelner Textstellen. Eine Tabelle will Werte, die in Zellen getippt werden, und Änderungen, die sich fortpflanzen. Ein Foliensatz will strukturelle Verschiebungen über Folien hinweg. Die Linse ist eines dieser Bearbeitungsverhalten, nicht ihr gemeinsamer Ursprung.

Ein Typ ist kein Schema, sondern ein Bündel von Affordanzen

In rewritable ist ein Typ weder ein Dateiformat noch ein statisches Schema. Er ist ein registriertes Bündel von Affordanzen: die Menge dessen, was die Runtime mit genau diesem Container anzufangen weiß. Sobald man Typ so definiert, ergibt sich etwas, das wir nicht geplant hatten: Das Typsystem und das Skill-System hören auf, zwei Systeme zu sein. Sie werden zu einem Kernel. Ein eingebauter Typ ist ein Bündel von Affordanzen, das mit der Datei ausgeliefert wird und als vertrauenswürdig gilt. Ein Skill von Drittanbietern ist ein Bündel von Affordanzen, das mit Herkunft, Berechtigungen und Isolation ankommt. Derselbe Mechanismus, anderes Vertrauen.

Eine Affordanz ist ein Beitrag zur Runtime: ein Verhalten, das der Kernel zu einem definierten Zeitpunkt aufruft. Es gibt fünf Arten:

  • view: rendert eine andere Ansicht derselben Datei (einen Präsentationsmodus, ein Grid, eine App-Oberfläche).
  • edit-surface: lässt einen Menschen strukturierte Inhalte direkt bearbeiten, ohne dass ein Modell beteiligt ist.
  • tool: stellt eine Operation bereit, die der Agent aufrufen kann („Spalte hinzufügen, die X berechnet“, „Zeilen markieren, in denen Y zutrifft“).
  • compute: leitet aus deklarierten Eingaben einen Wert ab und berechnet ihn neu, wenn sie sich ändern.
  • hook: beobachtet ein Lifecycle-Ereignis oder nimmt daran teil.

Ein Prosa-Dokument trägt eine einzige Affordanz: die Linse selbst, und die ist ein tool, die Agenten-Operation, die den Text neu schreibt. Eine Datatable trägt vier: eine Grid-view, eine direkte edit-surface für Zellwerte, ein tool für agentennative Tabellenoperationen und eine compute-Affordanz, die abgeleitete Zellen neu berechnet. Eine Präsentation fügt eine view für den Präsentationsmodus hinzu. Eine Anwendung fügt interaktive Bereiche hinzu. Das Dokument ist keine privilegierte Basis, an die die anderen angeschraubt sind. Es ist einfach das dünnste Bündel.

Deshalb ist die Tabellenkalkulation der nützliche Fall und nicht der unangenehme. Sie sprengt das Modell nicht. Sie zeigt, dass das Modell immer schon zwei Edit-Surfaces hatte und wir nur eine gebaut hatten: direkte Manipulation für den Menschen, die Linse für den Agenten. Es ist dieselbe Trennung zwischen dem Menschen und dem Agenten, die rewritable schon in seinem eigenen Bearbeitungsverlauf festhält, nur taucht sie jetzt innerhalb einer einzelnen Datei auf. Die Linse zu bevorzugen war immer eine Voreinstellung und nie ein Gesetz.

Typen sind First-Party-Skills

Das Einzige, was „den Grid-Editor des Datatable-Typs“ von „einer Diagramm-Erweiterung, die jemand heruntergeladen hat“ trennt, ist Vertrauen. Eine Datatable ist kein besonderes Objekt, das die Runtime im Voraus kennt. Sie ist ein Bündel von Providern, die zufällig mit dem Seed ausgeliefert werden und First-Party-Freigaben erhalten. Die heruntergeladene Erweiterung hat dieselbe Form: Sie registriert Provider, deklariert die Capabilities, die diese brauchen, und wird vom selben Kernel zu denselben Zeitpunkten über dieselbe Registrierungs-API aufgerufen. Der Unterschied liegt nicht im Mechanismus, sondern in Herkunft, Berechtigung und Isolation.

Mit Kernel meine ich etwas Bestimmtes und Kleines: die Runtime-Schicht, die registrierte Provider annimmt, die deklarierten Capabilities jedes Providers prüft, ihn zum richtigen Zeitpunkt im Lifecycle aufruft und seine Auswirkungen in die Datei zurückschreibt. Dieser Schicht ist es egal, ob ein Provider aus dem Seed oder aus einem Download stammt. Sie interessiert, welche Art von Provider es ist und was er anfassen darf.

Das heißt nicht, dass jeder Skill jede Affordanz bekommt. Die Provider-Art hängt vom Vertrauen ab. Eine First-Party-Datatable darf einen Grid-Editor im Main Thread registrieren, ein Drittanbieter-Skill mit wenig Vertrauen nur Worker-sichere Tools, Computes und Hooks. Der Mechanismus ist gemeinsam, die erlaubten Provider-Arten unterscheiden sich je nach Stufe. Diese Grenze haben wir nicht gewählt, sie wird uns aufgezwungen, und der nächste Abschnitt zeigt, warum.

Genau das macht daraus eine Verlagerung auf eine andere Schicht und kein Feature. Wir hatten das Typsystem und die Skill-Schicht als aufeinanderfolgende Arbeit behandelt: erst festlegen, was die vier Typen sind, und später entwerfen, wie Plugins sie erweitern. Tatsächlich sind sie ein einziges Designproblem über einem einzigen Kernel: Provider-Registrierung plus deklarierte Capability. Baut man sie getrennt, spezifiziert man denselben Mechanismus zweimal, und zwar schlecht. Baut man den Kernel einmal, ergeben sich die Typen daraus als First-Party-Skills.

Was aus runtime.on wird

Die Runtime trägt den Keim dieses Kernels schon in sich, nur lässt sie sich noch nicht erweitern. Heute ist runtime.on ein Benachrichtigungs-Bus: Code kann drei Lifecycle-Ereignisse abonnieren (commit, modify, status), aber nur im Nachhinein. Ein Listener erfährt, dass ein Commit stattgefunden hat. Er kann keine View registrieren, keine Edit-Surface beisteuern, den Commit nicht abfangen, kein Agenten-Tool bereitstellen und nicht an der Neuberechnung teilnehmen. Er beobachtet die Runtime, erweitern kann er sie nicht.

Der Kernel ist das, was aus diesem Bus wird, wenn er erwachsen wird: Aus dem reinen Beobachten von drei Ereignissen wird Provider-Registrierung über eine typisierte Menge von Beiträgen, durch Capabilities abgesichert und herkunftsbewusst. Capability hängt an der Provider-Art und nutzt die Berechtigungsgrammatik, die die Actions-Spezifikation bereits definiert: Eine View braucht nichts, ein reines Compute braucht nichts, ein Tool, das ins Netz geht, deklariert network:, ein Tool, das ein gespeichertes Geheimnis liest, deklariert vault:. Die Skill-Spezifikation in ihrer jetzigen Form deckt die Schranke ab (Installation, Berechtigungen, Signierung, Worker-Isolation) und schweigt zum Motor. Der Provider-Kernel ist dieser fehlende Motor, und er liegt unter den Typen ebenso wie unter der kontrollierten Skill-Schicht.

Zwei Befunde, die die Taxonomie erzwingt

Die Provider-Arten aufzuzählen ist der schwierige Teil, denn die Taxonomie ist keine Kosmetik. Zwei strukturelle Ergebnisse folgen direkt aus ihr, und beide schränken das Design ein, statt es zu schmücken.

Thread-Affinität ist die Vertrauensgrenze. Eine View und eine Edit-Surface brauchen das DOM. Sie können nur im Main Thread laufen. Deshalb lassen sie sich nicht in einer Worker-Sandbox einsperren, und die Worker-Isolation ist die gesamte Grundlage des Sicherheitskonzepts für nicht vertrauenswürdigen Code. Ein Drittanbieter-Skill, der seine eigene View malen oder eine eigene Edit-Surface besitzen will, lässt sich also konstruktionsbedingt nicht sandboxen und muss in einer höheren Vertrauensstufe sitzen als ein Skill, der nur ein Tool, ein Compute oder einen Hook beisteuert, denn die lassen sich alle sauber auf einen Worker beschränken. Welche Provider-Arten ein Skill registrieren darf, ist keine UX-Vorliebe. Das legt der Ort fest, an dem der Beitrag laufen muss. Vertrauensgrenze gleich Thread-Grenze gleich DOM-Zugriff.

Compute-Provider müssen rein sein. Der Compute-Provider macht „Neuberechnung als Affordanz“ erst real: Eine abgeleitete Zelle rechnet neu, wenn sich ihre Eingaben ändern. Und er ist ausdrücklich keine importierte Formel-Engine. Er ist darauf beschränkt, rein zu sein: keine I/O, deterministisch, von der Runtime orchestriert, und seine Ergebnisse gehen zurück in das Textmodell, das die Quelle der Wahrheit bleibt. Genau wegen dieser Reinheit braucht er keine einzige Capability, und genau deswegen darf er nicht zu Excel heranwachsen. Die Einschränkung ist das Feature. An dem Tag, an dem Compute nach .xlsx-Kompatibilität greift, sind wir wieder auf dem Weg zu dem Rechenprogramm, das wir bewusst nicht bauen wollten.

Offene Punkte und künftige Arbeit

Dieses Design legt den Kernel auf den kritischen Pfad. Prototypen für Präsentations- und Datatable-Vorlagen können wir ohne ihn bauen, aber als echte Typen ausliefern können wir sie nicht, denn ohne Kernel ist ein „Typ“ weiterhin das, was er heute ist: etwa sechs ersetzte Bereiche und ein Eintrag im System-Prompt, also eine Startvorlage und kein Affordanz-System. Die Provider-Taxonomie richtig hinzubekommen ist entscheidend, weil sich jeder Typ und jeder künftige Skill an sie bindet.

Und „Typ“ hat noch eine zweite Seite. Ein Container muss irgendwann deklarieren, wie andere Container ihn abfragen, ihn in einen Graphen einbinden, Arbeit an ihn delegieren oder von ihm abhängen können. Das ist ein anderes Problem als das hier. Der Provider-Kernel beantwortet, wie eine Datei weiß, wie sie sich selbst bearbeitet. Er beantwortet nicht, wie aus vielen Dateien ein System wird, und diese Schicht ist aufgeschoben, nicht gelöst.

Die Linse war die richtige erste Metapher, aber die falsche Grundeinheit. Sie gab jedem Typ ein einziges Verb und ließ die Datei vergessen, was sie war. Der Kernel ist der dritte Weg: eine Runtime, eine portable Datei und genau die Verhaltensweisen, die der Typ verlangt. Word wusste, dass es ein Dokument ist. Excel wusste, dass es ein Grid ist. Eine Datei, die sich selbst bearbeitet, sollte wissen, was sie ist. An diesem Teil bauen wir als Nächstes.

Aus dem Englischen übersetzt: zum Originalbeitrag

Gestalten Sie die Zukunft Ihres Unternehmens mit KI

Tauchen Sie ein in unsere spannenden Workshops und rüsten Sie Ihr Team mit den Werkzeugen und dem Wissen aus, um im Zeitalter der KI führend zu sein.

Kontaktieren Sie uns
Scroll to top