Die YouTube-Kanal-Fabrik Stand 2026-07-28 19:22 UTC

Pipeline

Liest die DNA und baut daraus das Video

🛣️ Die Straße – Migration von Fork-pro-Kanal auf EINEN parametrischen Workflow-Satz

Status: Richtung entschieden von Leon am 27.07.2026 (HZ-363). Kein Fork pro Kanal mehr – EINE parametrische Kette, durch die jeder Kanal mit seiner DNA/seinem Rezept läuft. Dies ist die einzige Quelle für den Migrationsplan. docs/fabrik_blaupause.md H4 (Weg A/B) verweist hierher; dort steht nur noch das Modell, nicht mehr die Abwägung. Verlauf/Changelog → docs/bereiche/youtube.md. Tickets → HZ-363 + Folgestufen.

1 · Warum das kein Risiko ist: die Vielfalt ist Werte-Vielfalt, keine Graph-Vielfalt

Leons Sorge beim Entscheid: „kritisch bei so vielen Arten – Stock, KI, Pexels etc.? Aber man kann ja schon noch angeben, welcher Prompt, welche Maße, welche Stills."

Gemessen am echten n8n-Stand am 27.07.2026 (102 Workflows, 64 aktiv; Messung read-only über die Public-API, Node-Namen + Parameter-Hashes je Stufe):

StufeKanäleStruktur-Übereinstimmung (Jaccard über Node-Namen)Nodes
publisher81.00 – byte-gleich10
p591.00 – byte-gleich8
p315Median 1.00 (16 gemeinsame Nodes)3–17
p412Median 0.79 – 21 Kern-Nodes von 3621–36
p115Median 0.5012–19
p215Median 0.39 (Union 162)31–78

Bei den 10 Zwillings-Kanälen (history, psych, cs, wisdom, geo, survival, doomed, worldcup, alvaro_horror, auswandern_rente_de) sind die Node-Namen je Stufe deckungsgleich. Abweichend sind nur Parameter-Werte:

Stufegemeinsame Nodesparameter-identischabweichend
p2432617
p421912
p316106
p1918 (fast nur Prompt-Texte)

Und die „vielen Arten" gibt es nicht. Alle Kanäle tragen dieselbe Quellen-Kette – ApiMart-KI-Zweig + Pexels→Pixabay→Wikimedia→Unsplash, optional getty / harvest-gw / openverse. Pro Kanal ist nur eine andere Teilmenge scharf, und welche Quelle einen Beat bedient, entscheidet schon heute der Claude-Node „Stock Query Router" zur Laufzeit (media=ai|stock je Beat). Die Quellen-Liste ist bereits ein Rezept-Feld (recipe.harvest_sources, wf_fork/patch_harvest_sources.py).

Die beiden scheinbaren Sonderfälle sind keine:

  • stickman (78 Nodes, 52 „eigene"): dieselbe KI-Kette 8× entrolltAI Image 1..8 je

Submit→Wait→Status→Done?→Download→R2-Upload – statt in einem Loop.

  • reddit: dieselbe ApiMart-Kette unter anderen Node-Namen („ApiMart - Submit Image" statt

„ApiMart Submit").

Was heute je Kanal wirklich abweicht, ist genau die Liste, die Leon behalten will: Webhook-Pfad · R2-Prefix · Trigger-URL · Voice-ID (Algrow-Node) · Router-Prompt = welche Stills · Skript-Prompt + Wortziel = welche Maße · Thumbnail-Prompt · Store-Key · Telegram-Text. Das sind Rezept-Felder, keine Workflow-Varianten.

2 · Das Muster existiert im Haus – n8n ist die letzte geforkte Schicht

  • 6 Gateways laufen schon parametrisch geteilt: pexels-search, video-db, claude-gen,

algrow, algrow-tts, tg-notify – je EIN Webhook-Pfad, von allen Kanälen gerufen.

  • 5 Render-Container bedienen 15 Kanäle (render-psychology allein 6). Der Kanal kommt als

channel / recipe_key im Body; fehlt channel, gibt es 400 (Constraint #11, HZ-814).

  • 0 Sub-Workflow-Nodes (executeWorkflow) im ganzen System – verkettet wird über HTTP-Webhooks.

Die Straße braucht also kein neues Muster, nur konsequente Anwendung des vorhandenen.

Wartungslast heute: 53 wf_fork/patch_*.py, davon ~20 mit hartkodierten Kanal-Listen/WF-ID-Maps. Jede neue Stellschraube = 1 Patch × N Kanäle × Constraint #7 (deactivate+activate) je Workflow. Jeder neue Kanal = 6 weitere Workflows, die alle künftigen Patches mitschleppen.

3 · Zielbild

Die fünf Regeln, die den Umbau tragen

  1. Kanal-Identität nur aus dem Pfad. Sie steht beim Aufrufer an genau einer Stelle, erscheint im

Log, und unbekannter Kanal = Abbruch vor der ersten Geldstelle.

  1. Der Bauplan wird nie mitgeschickt, immer nachgeschlagen. Ein Aufrufer kann kein Rezept fälschen.
  2. Kein stiller Default. Kein ||/?? in irgendeinem Body. Fehlendes Feld → stopAndError +

tg-notify. (Lesson HZ-814: genau so überlebte "channel":"HISTORY" als Default monatelang.)

  1. Alias-Auflösung zentral. Jeder Kanal hat heute drei Schreibweisen – Registry-Key geo,

store_channel: emptyearth, youtube.channel_param: GEO. (Bei cs sind store+YT bewusst history = der CS-Umbau, kein Bug.) Der Bauplan liefert alle drei explizit; kein Node bastelt sie sich selbst zusammen.

  1. Der Aktiv-Schalter ist Konfiguration. Heute lebt „läuft / läuft nicht" im n8n-active-Flag plus

node-disabled Cron (alle P1-Crons stehen auf 0 16 /2 *). 6 Workflows können keine 15×6 Zustände tragenenabled + cadence je Kanal/Stufe in registry.json, bevor irgendetwas umgeschaltet wird. Sonst ist am Umschalttag jeder Registry-Kanal „an" = 15× ApiMart parallel.

DNA-getrieben, aber ratefrei (Leons Entscheid + sein eigener Einwand)

Leon: „schon mit DNA direkt – das Problem ist halt, dass die DNAs bei den meisten Channels noch nicht ausgereift sind; alvaro ist am fortgeschrittensten." Gemessen ist das noch schärfer:

DNA-Reife (gemessen 27.07.)Kanäle
DNA vorhanden4 – alvaro_horror, auswandern_rente_de, geo, history
keine DNA, Rezept ist 350–600-Byte-Stub11 – cs, psych, wisdom, survival, doomed, worldcup, reddit, stickman, aviation, business, maritime
shots_per_min maschinenlesbar0 – die Werte sind Prosa: "unverifiziert", "15-30 (veri…", "stark templ…"

Auflösung: Die Straße rechnet immer aus dem Bauplan – nirgends ein Literal (H7-Gesetz). Aber sie rät nie. Jedes Bauplan-Feld trägt eine provenance:

  • dna – aus der DNA gerechnet (heute: alvaro/geo/history/rente, soweit maschinenlesbar)
  • pinned – heutiger Wert bewusst eingefroren, weil die DNA-Stelle fehlt/Prosa ist (sichtbare Lücke)
  • fehlt ganz → harter Stop, kein Default

Damit fährt ein reifer Kanal sofort DNA-getrieben, die Stub-Kanäle fahren sichtbar eingefroren weiter, und die Migration wartet nicht auf 11 DNA-Läufe. Die DNA-Reife wird messbar statt still zu Müll zu führen.

4 · Reihenfolge (Begründung = die Zahlen aus §1)

#StufeWarum hierRisiko
1publisher1.00 identisch · alle 8 AUS · Cron-Trigger → Constraint #7 greift nichtnull
2p51.00 identisch · sitzt hinter allen Geldstellenniedrig
3p3Median 1.00 · jede Divergenz ist ein Registry-Feld (Container-Host, Prefix, callback, recipe_key) · Render lokal = $0 prüfbarniedrig
4p40.79 · die Nicht-Kern-Nodes werden Rezept-Schalter (Thumbnail-Schule, eBook) · Upload erst nach upload_target_check.py grünmittel (YouTube)
5p2gebaut + belegt 27.07. (qUTlurAFjer8cbiD, 76 Nodes, deaktiviert)0.39 · beide Geldstellen (ApiMart + TTS). Kein Merge: der fetteste P2 (Psych/Rente, 74 Nodes) ist der Stamm, dünne Kanäle sind Teilmenge – 26/43 parameter-identisch belegen das. Beleg: echtes P1-Skript durch die Straße = 90 Beats, 20/14/14/14/14/14, identisch zum Fork bei demselben Run, $0 (HZ-406). Quellen-Mix wirkt (HZ-418, Exec 1751): wikimedia 31 · pexels 26 · openverse 17 · pixabay 16 statt 90× pexels. Offen vor dem Umschalten: HZ-430 (5 Fix-Beat-Kanäle ohne Rezept-Prompt → für die liefert der Bauplan gar keinen beat_modell und die Straße bricht sauber ab)hoch
6p1mechanisch am leichtesten (nur Prompts), aber P1 ist der Takt. Solange P1 geforkt bleibt, bleiben 15 Aktiv-Schalter als Gaspedalmittel

Canary = doomed (aktiv, kein Publikum, kein eBook-Funnel), danach alvaro. history / cs zuletzt – dort hängt der eBook-Funnel.

Blast-Radius-Kontrolle (ein Bug trifft dann ALLE Kanäle)

  • Die Straße entsteht als NEUER Workflow mit neuem Pfad, die Forks bleiben aktiv. Umgeschaltet wird

beim Aufrufer: eine URL (wf_fork/patch_*.py-Muster). Der PUT trifft damit nie den Fork.

  • Rückweg = dieselbe URL zurück. Fork wird erst nach zwei sauberen Läufen inaktiv gesetzt,

nie gelöscht.

  • Kill-Switch: enabled:false je Kanal/Stufe → Straße antwortet 423 und bricht ab.

Global: Bauplan-Gateway deaktivieren → alles fällt fail-closed aus (kein Lauf statt falscher Lauf).

  • Netz vor Schritt 1: channel_clone/backups/2026-07-27-hz363/ – alle 74 Kanal-Workflows

plus AKTIV_MAP.json (45 aktiv, inkl. Cron-disabled-Flags).

  • Verifikation: channel_clone/road_check.py diffed den aufgelösten Bauplan gegen die Werte in

den lebenden Fork-Workflows (read-only, Sekunden, $0). upload_target_check.py bleibt Pflicht-Gate vor jedem P4-Schritt. Doppelagenten-Abnahme nach Constraint #12.

4b · Stand: was am 27.07. gebaut und bewiesen wurde

Die Bauplan-Auflösung steht – sie ist die Grundlage aller sechs Stufen:

StückDateiWirkung
Auflösung Kanal+Stufe → alle Wertedashboard/bauplan.pyeine Quelle, provenance je Feld, kein stiller Default
HTTP-Zugangdashboard/app.py/hq/api/bauplan, /hq/api/bauplan/alle404 unbekannt · 409 Lücke (mit Feldnamen) · 423 Kill-Switch
7. Gatewaywf_fork/create_bauplan_gateway.py → n8n N4YwuXDZKNY7Wj48 (aktiv)POST /webhook/bauplan, Guard bricht ohne channel/stage ab
Stufe 1wf_fork/build_publisher_road.py → n8n MXVBcASOgDmYY8MG (deaktiviert)EIN Publisher für alle Kanäle statt 8 Klonen
Der Beweischannel_clone/road_check.pydiffed Bauplan gegen die lebenden Workflows, read-only, $0
Schalter + 4. Aliaschannel_clone/registry.jsonroad.enabled/road.auto, asset_prefixAktiv-Stand als Konfiguration statt als n8n-Flag

Belege (alle $0, keine Läufe ausgelöst):

  • Gateway gegen sechs Fälle: history/p3 → 200 · history/publisher → 423 · gibtsnicht/p2 → 404 ·

history/p2 → 409 (beats) · fehlendes stage bzw. channel → Guard bricht ab.

  • Trockenlauf der Publisher-Straße gegen eine Kopie der Registry (nie am Live-Topf):

history würde mit seinen eigenen Werten fahren (render-history-remotion · channel=HISTORY · store=history), alvaro wird wegen upload_mode=browser korrekt übersprungen. Gegen die echte Registry fährt sie niemanden – alle 8 stehen auf enabled:false.

  • road_check.py über alle 15 Kanäle × 6 Stufen: 162 Werte stimmen mit dem Fork überein,

3 Drift (unten), 25 benannte Lücken.

  • Reifegrad nach Stufen: publisher 8/8 · p5 9/9 · p4 12/12 · p3 12/15 wären heute fahrbar;

p2 klemmt an beats (14) und bildquellen (12), p1 an wortziel (15). Die 3 fehlenden p3 sind die Stubs (aviation/business/maritime).

  • Der Migrations-Handgriff funktioniert: road_check.py --freeze doomed --apply hat die

gemessenen Ist-Werte (beats: 48, bildquellen: [ai, pexels, pixabay]) mit voller Herkunft ins Rezept geschrieben → doomed/p2 ist seither vollständig fahrbar.

Was der Bau selbst zutage gefördert hat

  1. Es sind VIER Schreibweisen pro Kanal, nicht drei. Neben Registry-Key, store_channel und

youtube.channel_param gibt es den Asset-Prefix, und der weicht bei 5 von 12 Kanälen ab: cscs (Store: history), geogeo (Store: emptyearth), worldcupwm, redditreddit (Store: reddithorror), alvaro_horroralvaro. Er ist nicht ableitbar und steht jetzt gemessen als asset_prefix in der Registry.

  1. Render-Container ≠ Upload-Container. Bei geo, doomed, survival und worldcup wird auf

render-psychology/render-history-remotion gerendert, aber über render hochgeladen (youtube.render_container). Wer für Upload-Stufen den Render-Container nimmt, schickt /upload und /publish an den falschen Container – dieselbe Fehlerklasse wie HZ-814.

  1. Zwei Upload-Wege. alvaro_horror lädt bewusst über den AdsPower-Browser (HZ-290) und hat

absichtlich kein channel_param. Ein pauschales Pflichtfeld hätte den Kanal blockiert – oder jemanden verleitet, genau das Leck aufzureißen, das dort zugemauert ist.

  1. recipe.voice ist ein Key, keine Stimm-ID. Die Auflösung läuft über

channel_clone/voices.json (4.771er-Pool), nicht über registry.voices – dort steht ein alter Mini-Pool, in dem kein einziger Rezept-Key vorkommt.

  1. „36 Bilder fix" stimmt so nicht. Gemessen: psych 24 · worldcup 36 · wisdom/doomed/survival 48 ·

geo 72. Der Wert ist überall unsteuerbar, aber nicht überall gleich – wer bei der Migration pauschal 36 einsetzt, ändert vier Kanäle.

  1. Drei echte Drifts im Ist-Zustand (nicht durch den Umbau entstanden, von road_check gefunden):
  • history/p2: der Workflow spricht mit Johi (HRttR5MB…), Rezept und Registry sagen

oscar2 (3mmJ2Z…).

  • alvaro/p2: Workflow Viraj (1U02n4…), Rezept edoardo (YqZLNY…).
  • alvaro/publisher: ruft render:8080, laut Registry wäre es render-psychology:8080

(schlafend: Workflow aus, und der Kanal lädt ohnehin über den Browser).

5 · Sonderfälle

Kriterium: gleiche 6 Stufen + gleicher Store + gleicher Render-Vertrag + läuft → mitmigrieren. Läuft nicht → aus dem Stamm neu instanziieren statt umbauen. Anderer Vertrag → eigener Stamm.

  • aviation / business / maritime – 31-Node-Stubs, p1–p3 aktiv, kein p4/p5, kein Render-Container,

andere Datenschicht (dataTable statt Store): eigener Stamm gemeinsam mit den Shorts-WFs (S1–S3, dort liegt der Fork schon zweimal), nach dem Langform-Stamm. Bis dahin unangetastet.

  • stickman (komplett aus): nicht einrollen – die 52 entrollten Nodes tragen nur einen Index,

keinen Kanal. Aus dem Stamm-P2-Loop neu instanziieren, 78-Node-Fork exportieren + stilllegen.

  • reddit (aus; lebendes Geschwister alvaro): nur Node-Namen weichen ab, und Namen tragen die

$('…')-Expressions → Umbenennen ist reiner Verlust. Stilllegen, Registry/Recipe behalten.

6 · Die drei Fallen, die im Bau bewusst adressiert werden

  1. Der Aktiv-Stand ist Konfiguration (siehe Regel 5) – deshalb entsteht das enabled/cadence-Gate

in Stufe 1, wo es null Risiko hat, und nicht erst bei P2.

  1. Drei Kanal-Schreibweisen (Key / store_channel / channel_param) – der Store hat

UNIQUE(channel, run_id) und Assets liegen unter <channel>/<runId>: eine Verwechslung überschreibt fremde Zeilen und Assets. Der Bauplan liefert alle drei explizit.

  1. Observability schrumpft – 74 Execution-Ströme werden 6, und Webhook-Executions stehen nicht in

der Public-API (Constraint #8). Gegenmaßnahme im selben Schritt: Kanal UND Stufe in jedem tg-notify, Store-Write beim Stufen-Eintritt statt erst am Ende. Außerdem in Loops immer .first() statt .item (sonst „Can't determine which item" / falsches Pairing).

7 · Nicht Teil dieser Migration (eigene Tickets)

Render-Container-Konsolidierung (10 Container auf 7,6 GB RAM) · Shorts-Stamm · DNA-Reifung der 11 Stub-Kanäle (extract_dna.py, $0 über claude-proxy) · derive_format.py-Ausbau (Prosa→Zahl für est_length_min/shots_per_min, beats-Formel) · Weg A (ein Builder generiert die Workflows aus Rezept + Modul-Katalog, HZ-203).

Quelle im Repo: docs/pipeline_strasse_migration.md