# SEKTION 01 — NODES UND KATALOG

> Der Teil, der Global UI von ComfyUI unterscheidet. Zuerst bauen.
> Bestehender Code: `kern/knoten.py` (läuft, getestet).

---

## 1.1 Was ein Node ist

Ein Node hat **Eingänge** und **Ausgänge**. Eingänge sind entweder
Verbindungen von anderen Nodes oder Werte, die im Graphen stehen.

**Der Unterschied zu ComfyUI:** die Rechen-Einstellungen sind ebenfalls
Eingänge. Jeder rechnende Node bekommt sie **automatisch** über
`ausfuehrungs_eingaenge()`:

| Eingang | Werte | Wofür |
|---|---|---|
| `geraet` | auto · gpu · cpu | Wo DIESER Node rechnet |
| `praezision` | auto · fp32 · fp16 · bf16 · fp8 | Genauigkeit DIESES Nodes |
| `resident` | ja/nein | Modell nach dem Lauf im VRAM lassen |
| `verdraengen` | ja · nein · nur_fremde | Darf er andere Modelle rauswerfen? |
| `bei_engpass` | ausweichen · stueckeln · ablehnen · auslagern | Was tun, wenn der VRAM nicht reicht |

`verdraengen: nein` ist der Schalter, an dem die **gemessenen 6,2 Sekunden**
hängen. `bei_engpass` ist der Schalter gegen Windows' stilles Auslagern in
den geteilten Systemspeicher.

**Regel: wer einen neuen rechnenden Node anlegt, lässt diese fünf niemals
weg.** `Node.__post_init__` hängt sie an — nicht aushebeln.
`tests/test_kern.py` prüft es für jeden Node im Katalog.

## 1.2 Ein Node wird so angelegt

```python
_n("vae.dekodieren", "Bild", "VAE dekodieren",
   "Macht aus dem Latent das sichtbare Bild.",
   eingaenge=[
       Eingang("latent", Art.VERBINDUNG, von_typ="latent"),
       Eingang("vae",    Art.VERBINDUNG, von_typ="vae"),
       Eingang("kachel", Art.ZAHL, 0, min=0, max=4096,
               hinweis="0 = am Stück. Kacheln sparen Speicher, kosten Zeit."),
   ],
   ausgaenge=["bild"])
```

**Der `hinweis` ist Pflicht und kein Kommentar.** Er geht über
`KATALOG.fuer_die_ki()` an die KI und ist die Grundlage dafür, dass sie
Workflows bauen kann (Sektion 06). Ein Eingang ohne Hinweis ist für die KI
eine Blackbox. Schreib hinein, **wofür man ihn dreht** — nicht, wie er heißt.

## 1.3 Die Gruppen (Ziel: viertausend Nodes ab Werk)

des Nutzers Anspruch: von Basis breit, nicht nackt mit Nachrüst-Zwang.

| Gruppe | Datei | Inhalt |
|---|---|---|
| **Laden** | `knoten/laden.py` | UNet, VAE, Text-Encoder, LoRA, ControlNet, Upscaler, Embeddings, Quantisate |
| **Konditionierung** | `konditionierung.py` | Prompt kodieren, kombinieren, gewichten, Bereichs-Konditionierung, negativ, Stil-Suffix |
| **Sampling** | `sampling.py` | Sampler-Varianten, Planer, Schrittsteuerung, Teil-Rauschen, Verkettung |
| **Latent** | `latent.py` | leer, aus Bild, skalieren, zuschneiden, mischen, aus Vorrat |
| **Bild** | `bild.py` | dekodieren, kodieren, skalieren, zuschneiden, drehen, Farbe, Text drauf, speichern, laden |
| **Video** | `video.py` | Bild→Video, Frames, Endframe-Kette, Zwischenbilder, Zusammenfügen, Trimmen |
| **Audio** | `audio.py` | Musik, Stimme, Mischen, Länge |
| **Masken** | `masken.py` | erzeugen, invertieren, weichzeichnen, aus Segmentierung |
| **Steuerung** | `steuerung.py` | Bedingung, Schleife, Schalter, Wert setzen, Vergleich |
| **Werkzeuge** | `werkzeuge.py` | Notiz, Vorschau, Zeitmessung, Debug-Ausgabe |

**Vorgehen für die Breite:** Gruppe für Gruppe, jeweils vollständig, jeweils
mit Checks. Lieber eine Gruppe fertig als zehn halb. Nach jeder Gruppe
`PROJEKT.md` fortschreiben.

**Zählweise ehrlich halten:** ComfyUIs „4000" entstehen inklusive Custom
Nodes und Varianten. Wenn Global UI 600 eigene Nodes hat, schreib 600 hin —
keine Zahl aufblasen. Der Anspruch ist *breit ab Werk*, nicht *eine Zahl*.

## 1.4 Der Katalog

`KATALOG` ist die eine Registrierung. `eintragen()` wirft bei doppelten
Typ-Namen — Namenskollisionen fallen beim Start auf, nicht beim Nutzer.

Namensschema: `gruppe.was_es_tut`, klein, mit Punkt.
`modell.unet_laden` · `text.kodieren` · `vae.dekodieren` · `bild.speichern`

`KATALOG.fuer_die_ki()` liefert alles maschinenlesbar:
```json
{"anzahl": 8,
 "gruppen": {"Bild": ["bild.speichern", "vae.dekodieren"], ...},
 "nodes": {"vae.dekodieren": {"eingaenge": [
     {"name": "geraet", "art": "auswahl", "standard": "auto",
      "auswahl": ["auto","gpu","cpu"], "hinweis": "Wo dieser Node rechnet…"}]}}}
```

## 1.5 Was ein Node NICHT darf

- **Keine globalen Zustände lesen.** Kein `os.environ`, kein Startparameter,
  keine Datei außerhalb des Graphen, die sein Rechenverhalten ändert.
- **Nicht still korrigieren.** Ein unmöglicher Wert wird gemeldet
  (`Eingang.pruefe`), nicht heimlich gekappt. Genau daran ging bei Qwirbel
  ein 46-Sekunden-VAE-Decode monatelang unbemerkt durch.
- **Keine fremden Requirements** mitbringen.

## 1.6 Checks für diese Sektion

Bestehende in `tests/test_kern.py` erweitern:

- [ ] Jeder rechnende Node hat alle fünf Ausführungs-Eingänge *(steht)*
- [ ] Jeder Eingang hat einen `hinweis` — sonst ist er für die KI unsichtbar
- [ ] Keine doppelten Typ-Namen
- [ ] Namensschema `gruppe.was` eingehalten
- [ ] Jeder `von_typ` einer Verbindung kommt bei irgendeinem Node als Ausgang
      wirklich vor (sonst ist er nicht verdrahtbar)
- [ ] `fuer_die_ki()` enthält jeden Node und jeden Eingang
