aYOUne

Changelog

What changed — grouped by release, filterable by component and repository.

No milestone 2
New codegen

Riegel gegen den Sammel-Mount eines Rumpfes, der eine Kennung braucht

`actionAddressPlacement()` sagt, WO eine Aktion hingehoert — es sagt NICHT, ob der
vorhandene Rumpf dort bedienbar ist. Fuer `crm.Consumers` hat der Erzeuger sechs
`both`-Aktionen bereits EINMAL an die Sammel-Adresse gemountet (Commit 5bc61ad);
ihre Ruempfe lesen `req.params.id`, und Mongoose entfernt `_id: undefined` still
aus dem Filter — der Zugriff traefe einen BELIEBIGEN Datensatz des Mandanten.
Entdeckt wurde es von Hand, verhindert seither nur durch einen Hand-Haertungs-
Marker an der Router-Datei, also durch ABWESENHEIT der Route.

Neu: `collection-safety.ts` prueft den BESTEHENDEN Rumpf vor dem Sammel-Mount.
Kein `req.params.id` -> sicher. Mit kanonischem Waechter -> sicher. Datei existiert
noch nicht -> sicher (die Vorlage traegt den Waechter). Sonst wird der Mount
VERWEIGERT und AUSGEWIESEN (`[skip-unsafe-collection-mount]`), mit Grund UND
Ausweg — ein stilles Auslassen waere dieselbe unsichtbare Mechanik wie das stille
Setzen.

🔴 KOMMENTAR-BEWUSST, und das ist die teuerste Falle: `actionStreamRegenerate`
(cms.Streams) erwaehnt `req.params.id` VIER MAL in seinem Kopfkommentar, um zu
dokumentieren, dass es die Kennung eben NICHT von dort liest. Eine rohe Textsuche
verweigert dort einen Mount, der voellig in Ordnung ist — nach dem zweiten solchen
Fehlalarm schaltet jemand den Riegel ab.

FAIL-CLOSED mit ausdruecklichem Ausweg: erkannt wird nur die kanonische Waechter-
Form der Vorlage; wer einen anderen Stil faehrt, setzt den Marker `✅ SAMMEL-SICHER`.
Ein Irrtum laeuft damit immer in die sichere Richtung.

⚠ Beim Bau selbst getroffen: eine dynamisch gebaute Regex ueberlebt weder `node -e`
noch ein Heredoc (`'if\s*\('` wurde zu `'if\s*\('`, die Regex las `ifs*(`, und
der Waechter fand NIE einen Waechter). Die Waechter-Erkennung laeuft deshalb ueber
einen leerraum-normalisierten Zeichenketten-Vergleich, backslash-frei.

Proben: 20 Faelle mit Umkehrproben (mit Waechter schweigt der Riegel), zwei
Kommentar-Fallen samt Positiv-Kontrolle zum Strippen, Negativkontrollen (Waechter
auf ANDERER bzw. LAENGERER Variable zaehlt nicht; ASCII-Ersatzform des Markers
traegt nicht), sowie Proben gegen den ECHTEN Bestand und die ECHTE Vorlage.

Verify-Gate am echten Erzeuger beidseitig gefahren (`codegen routes --module crm
--dry-run`): alle sechs gehaertet -> kein verweigerter Mount; einen Waechter
temporaer entfernt -> Mount VERWEIGERT mit benanntem Grund; byte-genau
wiederhergestellt. Reihe 4830 (+20), die 6 roten sind beidseitig als vorbestehend
belegt (Fehlerlisten vor/nach identisch).

Brief: crm-consumers-both-aktionen-und-sammel-rechte-fundament-fix
Session-Id: crm-consumers-both-aktionen-und-sammel-rechte-fundament-fix-TBD

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012LmDa2yAaQZtJrAss6EuZ8
Fix codegen

unbefuellter Aktions-Rumpf verweigert laut (422) statt still 200

Bis hierher verwarf ein Rumpf mit leerer ALLOWED_FIELDS jedes Rumpf-Feld,
schrieb nur noch `_id` und antwortete 200 mit dem unveraenderten Dokument —
fuer den Aufrufer von Erfolg nicht zu unterscheiden. Genau dieses Bild hat
den Etikettendruck der Lagerplaetze sieben Wochen lang stillgelegt.

Der leere Vorgabewert bleibt RICHTIG (fail-closed; der Erzeuger kann die
Felder einer Aktion gar nicht kennen). Geaendert ist, was der Rumpf damit tut.

- 422, nicht 501: 501 hiesse „nicht auf diesem Wirt" und trifft nicht zu; die
Aktion IST zustaendig, sie hat nur keinen Rumpf. Vorbild: die dreifach im
Bestand umgesetzte `refuseUnimplementedAction` (hr/config).
- Der Sammel-Zweig behaelt sein 501 — dort ist die ADRESSE unbedienbar.
Reihenfolge test-gepinnt: 501 greift VOR 422.
- Kein Schalter, kein Opt-out: sobald ein Feld opt-in ist, faellt der Zweig
weg und der Pfad laeuft unveraendert.
- Die Kopf-Prosa beider Varianten nachgezogen; die emits-Variante sagt
ausdruecklich, dass auch KEIN Ereignis mehr feuert (die Verweigerung greift
vor dem Ereignis-Block).

Belege: echter Erzeuger-Lauf gegen cms/WebPages in einem Wegwerf-Ziel, der
erzeugte Rumpf gelesen UND uebersetzt (npm run build Exit 0), danach voll
zurueckgenommen (Arbeitsbaum sauber, Aktions-Verdrahtung 1 -> 2 -> 1).
11 neue Proben inkl. Kontrollfluss-Nachbildung und Flip (ohne die Wache 6 rot).
Volle Reihe 4709/4717 — die 8 roten sind vorbestehend und beidseitig belegt.

⚠ first-write-wins: wirkt NUR auf kuenftige Stuempfe, die 146 Bestands-
Fundstellen bleiben unveraendert. Der Melder zaehlt einen verweigernden Rumpf
weiter — gemessen und richtig: er misst Funktionslosigkeit, nicht Stille.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>