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
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