Files
planer2/LEARNINGS.md
2026-07-29 15:19:41 +02:00

452 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Learnings
Was beim Bau von planer2 gemessen wurde. Nicht was plausibel klang — was sich
nachweisen ließ. Geschrieben, bevor Prüfung 3 entfernt wurde, damit ihr Wissen
bleibt.
Stand: 29.07.2026
## Der Aufbau in einem Absatz
Markdown-Dateien sind die Wahrheit. Eine Karte ist ein Auftrag, eine Funktion
etwas, das man für sich testen kann, eine Regel eine Zusicherung. Der Code eines
fremden Projekts ist Beleg, nie Quelle der Wahrheit. Drei Prüfungen glichen ab:
Stil, „hat jede Funktion Code" und „hat jede Codestelle eine Funktion".
## 1. Was funktioniert hat
### Beweislast statt Meinung
Jede Aussage über den Code muss eine wörtlich zitierte Zeile mitbringen.
`quellcode.belegt()` schlägt sie gegen die Datei. Ein misslungenes Zitat zählt
nicht als Fund.
Das ist der wichtigste Baustein des ganzen Systems. Ohne ihn schlug ein früher
Versuch vor, gültige Inhalte zu löschen — das Modell urteilte direkt und lag
falsch. Mit ihm ist ein Fund nachprüfbar und ein Nichtfund die einzige Aussage,
die überhaupt Stimmen braucht.
**Die Asymmetrie ist der Hebel.** Vorhandensein lässt sich zitieren,
Nichtvorhandensein nicht. Also: ein geprüfter Fund genügt zum Freispruch, sechs
Fehlversuche sind die Anklage.
### Das Urteilsgedächtnis
Ein Urteil kostet sechs Anfragen und fällt bei Grenzfällen mal so, mal so. Genau
daran scheiterte die Wiederholbarkeit: derselbe Stand lieferte in Runde 1 einen
Befund, in Runde 2 keinen, in Runde 3 wieder einen.
Gespeichert wird deshalb das Urteil, nicht nur das Ergebnis (`ledger.py`,
`.pruefung.json` im Projektordner). Ein Eintrag gilt weiter, solange seine
Voraussetzung nachweisbar dasteht:
- ein Beleg, solange die zitierte Zeile noch in der Datei steht
- eine Fehlmeldung, solange sich am Quelltext nichts geändert hat
Das machte gleichen Stand zu gleichem Ergebnis. Ohne dieses Gedächtnis gibt es
keine Konvergenz — der Loop würfelt jede Runde neu.
**Der Zuschnitt des Fingerabdrucks entscheidet über die Kosten.** Anfangs ging
der Abdruck über den ganzen Funktionstext. Eine Stilkorrektur an einer Regel
tötete damit auch das Inhaltsurteil. Gemessen: R1 code 384 Anfragen, R2 code 384
Anfragen — null Treffer im Gedächtnis. Nach der Kürzung auf Karten- und
Funktionstitel: R3 feature 30 statt 259, R3 code 21 statt 201. Rund 88 %
Trefferquote, sobald die Stiländerungen abgeklungen sind.
Regel daraus: **ein Urteil verfällt nur, wenn sich ändert, worauf es tatsächlich
beruht.** Nicht wenn sich der Text drumherum ändert.
### Frühabbruch statt fester Stimmenzahl
Sechs Stimmen je Einheit waren gemessen richtig für die *Schwelle*, aber
verschwenderisch für den *Normalfall*. Ein nachgeschlagener Beleg beendet die
Frage — die anderen fünf Antworten wurden bezahlt und weggeworfen.
Stufen (1, dann 2, dann 3) mit Abbruchprüfung nach jeder Stufe:
- Prüfung 2: von 6 auf ~1 Anfrage im Normalfall
- Prüfung 3: von 6 auf ~3
Gesamter Loop auf planer2: **2719 → 1354 Anfragen** bei gleicher Rundenzahl.
**Eine Falle dabei:** Eine ausgefallene Stimme ist keine Ja-Stimme. Der erste
Wurf brach ab, sobald die verbleibenden Stimmen die Schwelle rechnerisch nicht
mehr reißen konnten — und hielt damit einen HTTP-429 für „ist abgedeckt". Fix:
nur abbrechen, wenn alle gestellten Fragen auch beantwortet wurden.
### Schwellen misst man, man rät sie nicht
Alle Zahlen in `inhalt.py` stammen aus Messungen an gepflanzten Lücken:
- `FEHLT_AB = 4` von 6 — eine echte Lücke war immer einstimmig; strittige Stellen
lagen darunter und kippten zwischen Läufen
- `TITEL_KANAL = 0.85`, `INHALT_KANAL = 0.7` — darunter explodierten die
Kandidatenpaare
- `KERN_MIN = 3` — unter drei Wörtern kennt die Überlappung nur 0, 0,5 und 1
- `BUENDEL = 6` Stellen je Anfrage — größere Bündel verloren Stellen aus der Mitte
Der Versuch, Grenzfälle *lexikalisch* zu filtern, ist gescheitert: „Produkt
merken" und „Konfiguration merken" sehen identisch aus, einer ist eine echte
Lücke, der andere nicht. Die Lösung war eine Entscheidung, keine Formel:
empfindlich sein (4 von 6) und Ablehnungen dauerhaft merken.
### Der Musterkatalog als Daten
Was eine auslösbare Stelle ist, steht in `muster/*.toml`, nicht im Code. Ein neues
Rahmenwerk ist eine Datei, keine Codeänderung.
Auslöser dafür: Bei einem Shopware-Plugin fand das Inventar genau *eine* Stelle,
weil Twig, Symfony-Attribute und `element.addEventListener` als Regex im Programm
nicht vorkamen. Nach dem Katalog: 19 Stellen.
Zwei Nachbesserungen, die viel ausmachten:
- `store.reroll()` ist die Fähigkeit `reroll`, nicht `store`. Ohne diese Regel
fielen zwölf Knöpfe eines Stores auf einen einzigen Eintrag zusammen.
- Symfony schreibt Routen benannt (`path: '/x'`) **oder** positionell
(`Route('/x', ...)`). Nur die benannte Form zu kennen fand 5 von 127 Routen.
### Erzeugen aus dem Inventar, nicht aus dem Quelltext
Der Erzeuger geht von den Stellen aus, nicht vom Code als Ganzem. Damit ist
Vollständigkeit Bauart, nicht Hoffnung: jede Stelle bekommt eine Funktion, jede
Funktion stammt von mindestens einer Stelle.
Was das Modell frei aufzählt, war jede Runde anders, und niemand konnte sagen, ob
etwas fehlt.
Vier Schritte: benennen (je Stelle) → falten (gleiche Titel zusammenlegen) →
verdichten (alle Funktionen nebeneinander neu ordnen) → füllen (je Funktion Ziel,
Regeln, Testschritte aus dem Code).
**Verdichten ist der Schritt, an dem Minimalität entsteht.** Ohne ihn kamen aus
21 Stellen 17 Karten mit je einer Funktion. Mit ihm: 5 Karten, 19 Funktionen.
### Nachfassen statt Verlust
Fällt eine Anfrage aus, fehlen sechs Stellen auf einmal. Bei 19 Stellen ist das
fast die Hälfte — und die Karten waren still unvollständig. Gemessen: 8 von 19
Stellen blieben unbenannt.
Fix: kleinere Bündel nachfragen (6 → 2 → 1), und was auch einzeln keinen Namen
bekommt, aus dem Schlüssel benennen. Ein grober Titel fällt auf; eine fehlende
Stelle fällt niemandem auf.
Dasselbe Muster beim Verdichten: fiel eine Zuordnung aus, blieben ihre zwölf
Funktionen auf Einzelkarten stehen — aus 19 Fähigkeiten wurden wieder 16 Karten.
## 2. Was nicht funktioniert hat
### Prüfung 3 — drei Konstruktionsfehler
Die Prüfung „hat jede Codestelle eine Funktion" hat nie zuverlässig funktioniert.
Nicht wegen des Modells, sondern wegen der Grundmenge, gegen die sie zählt.
Gemessen an planer2 (64 Stellen, 45 Funktionen):
**1. Eingabefelder fehlen ganz.** `v-model="suche"` ist kein Muster. Vier solcher
Felder im Projekt, keins im Inventar. Die Feature-Suche existiert, wird aber nie
gezählt und nie gemeldet.
**2. Argumente fallen weg.** Der Schlüssel ist der Funktionsname. Alle vier
Prüfknöpfe rufen `startePruefung(projekt, art)` → eine Stelle statt vier. Vier
Fähigkeiten, ein Punkt.
**3. Gleichnamige Funktionen fallen zusammen.** `alleAnnehmen` gibt es in
`FeatureKarte.vue` und in `FeatureListe.vue` — zwei verschiedene Dinge, ein
Punkt. Der neue Sammelknopf „Alle N Karten anlegen" ist dadurch unsichtbar.
Ergebnis: Gegen das eigene Inventar meldete Prüfung 3 **62 von 64 = 97 %**. Gegen
das, was das Programm wirklich kann, waren es **rund 44 von 52 = 85 %**.
**Dazu zwei falsche Abgedeckt-Urteile.** `DELETE /pruefung` und `GET /chat`
tragen keine Funktion. Prüfung 3 meldete null Lücken — das Modell hielt sie für
gedeckt, weil eine ähnlich klingende Funktion danebenstand.
### Zusicherungen ohne Auslöser sind unsichtbar
Der größte Fund, und er gilt weit über Prüfung 3 hinaus.
Vieles, was ein Programm zusichert, hängt an keinem Auslöser: eine Beschriftung
im Markup, eine Vorbelegung beim ersten Aufruf, die Reihenfolge von Dingen, ein
Standardfall, eine Grenze.
Gemessen an MtoVariantConfigurator: Von acht Anforderungen fehlten **fünf** auf
den erzeugten Karten, obwohl der Code sie umsetzte. Transitivität der Dropdowns,
Reihenfolge aus dem Backend, Vorbelegung aus dem Elternartikel, Schritt-Badge,
Hinweistexte. Alle vorhanden, alle unsichtbar.
Die Vollständigkeitsprüfung meldete dabei **null Lücken** — sie zählt nur
Auslöser.
**Der Fix, der wirkte:** Karten bekamen eigenes Ziel und eigene Regeln, gefüllt
aus den *ganzen Dateien* statt aus fünf Zeilen um die Stelle. Dazu ein
Nachtrag-Schritt je Karte: „was steht im Code und fehlt hier?". Danach 8 von 8.
**Was nicht wirkte:** Der Prompt allein. „Nenne die Sache, nicht die Umsetzung"
stand von Anfang an drin und half nicht.
### Dubletten: Zeichenähnlichkeit fängt Typ 4 nicht
„Galerie vorwärts blättern" und „Galerie nächste anzeigen" sind dieselbe Sache.
Gemessene Titelähnlichkeit: **0,53**. Schwelle: **0,85**. Das Paar wurde nie
Kandidat — kein Modell hat es je gesehen.
Die Klon-Typologie erklärt es: Typ 1 (exakt) und Typ 2 (umbenannt) fängt
String-Matching. Typ 4 (gleiche Bedeutung, andere Worte) nicht.
**Der Fix:** ein vierter Kanal — alles auf derselben Karte wird Kandidat.
Bezahlbar, weil eine Dublette fast immer neben ihrer Zwillingsschwester steht.
Zehn Funktionen ergeben 45 Paare, nicht Tausende. Fand sofort zwei echte
Dubletten, die vier Runden lang durchgerutscht waren.
### Streuung: gemessen, nicht behoben
Gleicher Code, gleiche Einstellungen, andere Karten. Lange nur eine Beobachtung,
dann eine Zahl.
Adjusted Rand Index über die Zerlegung der *Codestellen* (Titel ändern sich
zwischen Läufen, Stellen nicht):
| | Mittel | Minimum |
|---|---|---|
| Karten | **0,34** | 0,28 |
| Funktionen | **0,53** | 0,51 |
Kartenzahl über drei Läufe: 9, 9, 13.
0,34 heißt: die Kartenzuordnung ist näher am Zufall als an einer Entscheidung.
Das ist der ungelöste Kern des Erzeugers.
Was die Streuung *senkte*, aber nicht beseitigte: die Codezeile als Anker beim
Umbenennen. Ohne sie wurde aus „Konfigurator öffnen" ein „Erweiterung
aktivieren" — das Modell sah nur den Titel.
### Der volle Stilkatalog verdirbt Struktur-Antworten
Nach Kartentiteln gefragt, antwortete das Modell mit ganzen Karten samt
Testschritten. Die Beispiele im Katalog sind stärker als die Formatangabe.
Fix: nur die Titelregeln mitgeben. Allgemeine Lehre — **gib einem Schritt nur
den Teil des Katalogs, den er braucht.**
### Zu viel Parallelität
Vier gleichzeitige Läufe → HTTP 429. Ausgefallene Stimmen sahen aus wie „nichts
gefunden". Nacheinander laufen lassen war die Lösung, nicht mehr Wiederholungen.
## 3. Was aus der Recherche belegt ist
Eine Recherche zu Verfahren für vollständige und minimale Extraktion lieferte
Belege für einiges, was hier gebaut wurde, und ein paar Warnungen.
**Bestätigt:**
- *Adaptive Consistency* (Aggarwal et al., EMNLP 2023): Frühabbruch senkt das
Stichprobenbudget „by up to 7.9 times with an average accuracy drop of less
than 0.1%". Deckt sich mit der hier gemessenen Halbierung.
- *Early cutoff* aus der Build-System-Forschung (Mokhov et al., ICFP 2018): ein
Urteil verfällt nur, wenn sich seine echten Abhängigkeiten ändern. Genau das
Problem des zu groben Fingerabdrucks.
- *Mutanten als Ersatz für echte Fehler* (Just et al., FSE 2014): 73 % Kopplung
über 357 echte Fehler. Rechtfertigt gepflanzte Lücken als Vollständigkeitsmaß —
mit der Einschränkung, dass rund ein Viertel ungekoppelt bleibt.
- *Extraktive statt abstraktive Erzeugung* senkt Halluzination messbar. Hier: das
Zitat, das gegen die Datei geschlagen wird.
**Gewarnt:**
- Chao1 und Capture-Recapture schätzen Vollständigkeit systematisch zu niedrig,
besonders bei kleinen Stichproben. Für 19 Einheiten wertlos.
- Testsuite-Minimierung erkauft Größenreduktion mit Erkennungsverlust: „over 70 %"
Reduktion, „around 12.5 %" weniger gefundene Fehler. Aggressive Minimalität hat
einen Preis.
- Self-Consistency hilft bei konvergenter richtiger Antwort und *schadet* bei
systematischem Bias. Mehr Stimmen ersetzen keine bessere Verankerung.
**Nicht anwendbar hier:** Dynamische Invariantenerkennung (Daikon) und
Coverage-Kriterien brauchen einen *laufenden* Zielprozess mit Tests. Das System
liest nur Dateien fremder Projekte.
## 4. Synchronisation zwischen Planung und Code
Zweite Recherche, gezielt auf die Frage: wie hält man eine fachliche Beschreibung
und den Code dauerhaft synchron, in beide Richtungen? 25 Behauptungen gegengeprüft,
13 überlebt, 12 verworfen.
### Beide Richtungen enden bei etwa der Hälfte
**Planung → Code: 53,5 %.** E2EDevBench (50 reale PyPI-Projekte, Anforderungsdokument
als einziger Eingang) misst 53,50 % umgesetzte Anforderungen in der besten
Konfiguration. Ein unabhängig gebauter Benchmark mit anderen Autoren und anderen
Agenten-Rahmenwerken kommt auf 53,75 %. „The other half of the requirements
remained unfulfilled."
Die Abnahme durch einen Menschen ist damit kein Sicherheitsgurt, sondern die
gemessene Notwendigkeit.
**Code → Planung: 59 %.** Polikarpova, Ciupa, Meyer (ISSTA 2009, 25 Klassen, 831
menschliche Klauseln, über 19.500 abgeleitete): Automatische Inferenz findet 59 %
aller von Programmierern geschriebenen Zusicherungen wieder — mit kleiner
Testsuite nur 50 %. Autorenfazit: „contract inference cannot completely replace
the manual work of writing assertions."
Und die Ausbeute ist verrauscht: 90 % der abgeleiteten Klauseln sind korrekt, aber
nur **64 % relevant**. Rund ein Drittel muss aussortiert werden.
### Der brauchbarste Einzelbefund
Der Engpass ist **nicht das Denkvermögen, sondern der Ausdrucksvorrat**.
Von der Abdeckungslücke gehen 31 Prozentpunkte auf „nicht ausdrückbar" und nur
etwa 10 auf „ausdrückbar, aber nicht gefunden" — Verhältnis rund 3:1. Und von den
nicht ausdrückbaren Klauseln scheiterten **54 % allein daran, dass sie eine
Funktion mit einem Argument aufrufen**, weitere 19 % an fehlenden
Implikations-Schablonen.
Die Autoren widersprechen ausdrücklich der naheliegenden Deutung: „It is tempting
to draw the conclusion that at present the tool cannot compete with humans on
higher levels of abstraction. However … 'abstract' assertions are mostly not
expressible by the tool."
Übertragen auf uns, als Hypothese ohne Messung: dem Extraktor das Fachvokabular
mitzugeben — Funktionsnamen, Domänenbegriffe — schlägt vermutlich ein besseres
Modell.
### Die Beleglücke ist der eigentliche Befund
Für drei Dinge liefert der ganze Korpus **keinen einzigen belegten Mechanismus**:
- **Inkrementelle Synchronisation** aus Commits, Diffs, Pull Requests. Alles
Gemessene ist Greenfield-Vollerzeugung.
- **Drift-Erkennung ohne Vollvergleich.** Die einzige geprüfte Behauptung dazu —
Invarianten als Verhaltens-Fingerabdruck — wurde 1:2 verworfen.
- **Zwei-Wege-Konflikte.** In dem untersuchten Spec-Driven-Rahmenwerk kommen die
Begriffe *traceability*, *drift*, *bidirectional* und *round-trip* **null mal**
vor. Diese Verfahren sind einbahnig.
Das heißt nicht, dass es nicht geht. Es heißt, dass niemand es gemessen hat.
### Was gemessen wurde und fast nichts brachte
Prozess- und Strukturarbeit auf der Spezifikationsseite:
- Kontext-Hooks in einem Vier-Phasen-Ablauf (Specify → Plan → Tasks → Implement):
**+3,0 %** der Skala
- Spezifikation nach Epics gliedern: **+1,4 Prozentpunkte** Abdeckung, gleichzeitig
**−4,0 Prozentpunkte** auf der lexikalischen Messgröße
Der einzige stabile Gewinn kommt aus der Erdung im echten Code und aus
ausführbaren Testsuiten. Das deckt sich mit unserem eigenen Fund: der Prompt allein
half nie, das Zeigen ganzer Dateien half sofort.
### Verworfen — und nicht durch die Hintertür zurückholen
Sechs Mechanismen, die für unsere Architektur naheliegend gewesen wären, haben die
Gegenprüfung nicht überstanden:
| Behauptung | Abstimmung |
|---|---|
| Invarianten-Vergleich als Drift-Fingerabdruck | 1:2 |
| LLM-Richter je Anforderung als referenzfreie Abdeckungsmessung | 0:3 |
| Spurious Scenario Rate als Überspezifikations-Melder | 0:3 |
| Einbettungs- statt Wortabdeckung als Messgröße | 0:3 |
| Daikon-Präzision über 95 % gegen ESC/Java | 0:3 |
| Ein Zwischenartefakt Plan/Design schade der Treue | 0:3 |
Besonders bitter: der Fingerabdruck-Gedanke. Er hätte genau unsere Drift-Frage
gelöst.
### Ein Widerspruch, der offen bleibt
Die Behauptung, Inferenz decke systematisch Zusicherungen auf, wo kein Mensch
etwas notiert hatte — im Mittel 4,9-fach so viele relevante Klauseln, 13,3-fach bei
Schleifeninvarianten — wurde als eigenständige Behauptung **0:3 verworfen**.
Dieselben Zahlen tauchen aber in der bestätigten Belegkette einer anderen
Behauptung wieder auf. Der Widerspruch ist ungelöst.
Die Zahlen gelten damit nicht als belegt. Die Richtung — Extraktion ergänzt den
Menschen, ersetzt ihn nicht — ist mehrfach gestützt.
### Grenzen dieser Recherche
- **Alter.** Die härtesten Zahlen (59 %, 64 %, 54 %) sind von 2009 und hängen am
damaligen Schablonensatz. Sie sind **keine Obergrenze für LLM-Extraktion** — dazu
existiert keine Messung.
- **Quellenlage.** Vier der sechs tragenden Quellen sind unbegutachtete Preprints.
Begutachtet sind zwei plus eine Industriefallstudie.
- **Transfergrenze.** Alle harten Zahlen messen maschinenprüfbare Artefakte —
ausführbare Vor- und Nachbedingungen, Eiffel-Kontrakte, Gherkin. Unsere Planung
ist Prosa für Projektmanager. Der Schluss von „59 % der formalen Zusicherungen"
auf „x % der fachlichen Beschreibung" ist Plausibilität, keine Messung.
- **Zirkularität.** Die 53,5 % beruhen auf einem Modell als Richter, das teilweise
eigene Ausgaben bewertet.
### Was das für planer2 heißt
- Prüfung 2 sitzt auf dem belegten Teil. Beleg gegen die Datei geschlagen, ein Fund
genügt, ein Nichtfund braucht Mehrheit.
- Prüfung 3 hätte auf dem unbelegten gesessen. Das Streichen war richtig — und
jetzt auch von außen gestützt.
- Der inkrementelle Normalfall ist Neuland. Kein Beleg dagegen, aber auch keiner
dafür. Wer ihn baut, misst selbst oder weiß nichts.
- Die Kostenlage stützt ihn trotzdem: Vollsynchronisation kostete im Benchmark
~7 $ und 5,24 Mio. gesendete Token je Projekt — für 53,5 %.
## 5. Handkarten gegen erzeugte Karten
Ein direkter Vergleich auf MtoVariantConfigurator.
| | Handkarten | Erzeuger |
|---|---|---|
| Runden bis still | 2 | 3 |
| Anfragen | 361 | 1044 |
| Karten | 7 | 4 |
| Funktionen | 26 | 17 |
| Anforderungen erfüllt | 8 von 8 | 5 von 8 |
Die Handkarten entstanden aus Issue, Wiki **und allen 47 Kommentaren** plus dem
Code. Die Prüfungen änderten daran nur drei Stilkleinigkeiten.
Der Unterschied liegt nicht bei den Funktionen — die findet der Erzeuger. Er
liegt bei den Kartenregeln, also bei den Zusicherungen ohne Auslöser.
**Ein Fehler dabei, der eine eigene Lehre ist:** Beim ersten Anlauf habe ich nur
Beschreibung und Wiki gelesen und „8 von 8 erfüllt" gemeldet. Die 47 Kommentare
standen in derselben Datei. Die Zahl war falsch, weil die Grundmenge falsch war.
Wer Vollständigkeit misst, muss zuerst prüfen, ob er die Quelle ganz gelesen hat.
## 6. Zahlen zum Nachschlagen
Vier Projekte, Loop aus Erzeugen und drei Prüfungen bis zur Ruhe.
| Projekt | Dateien | Stellen | Karten | Funktionen | Runden | Anfragen |
|---|---|---|---|---|---|---|
| MtoVariantConfigurator | 19 | 19 | 4–7 | 17–26 | 2–3 | 361–1044 |
| tft | 44 | 21 | 5 | 20 | 3 | 616 |
| planer2 | 34 | 64 | 8–13 | 46–51 | 4–5 | 1354–2719 |
| MtoRagSystem | 475 | 183 | 23–33 | 150–168 | 5+ | ~4000 |
MtoRagSystem: 6,6 Mio. Zeichen Quelltext. Prüfung 2 schickte anfangs alles je
Funktion und fiel für das ganze Projekt aus. Mit Vorauswahl (erst fragen, welche
Dateien, dann nur die zeigen): 149 von 150 Funktionen belegt, 0 Fehler.
## 7. Offene Fragen
- **Streuung.** ARI 0,34 bei den Karten. Verankerung half, löste es nicht.
Deterministische Gruppierung wäre reproduzierbar, aber nicht zwingend richtig.
- **Grundmenge für Zusicherungen.** Karten-Regeln plus Nachtrag-Schritt haben den
konkreten Fall gelöst. Ein *zählbares* Maß dafür gibt es nicht.
- **Belege je Funktion.** Prüfung 2 merkt sich nur einen Beleg — den ersten, der
sich nachschlagen ließ. Für eine spätere, deterministische Abdeckungsrechnung
bräuchte sie alle.
- **Körnung.** Wann sind zwei Dinge eine Funktion, wann zwei? Es gibt kein
belegtes absolutes Maß dafür ohne Referenzmodell.