diff --git a/server/pruef-anruf-klingelt.mjs b/server/pruef-anruf-klingelt.mjs
index cc2d5b2b..a6d5c0d9 100644
--- a/server/pruef-anruf-klingelt.mjs
+++ b/server/pruef-anruf-klingelt.mjs
@@ -140,8 +140,20 @@ pruef("ein Anruf weckt alle außer dem Anrufer",
pruef("und die Art „anruf\" geht bis zur Benachrichtigung durch",
/chatEreignis\(raumId,\s*\{[\s\S]*?art:\s*"klingelt"[\s\S]*?\},\s*wecken,\s*"anruf"\)/.test(anruf));
+/* `.size` UND NICHT `.length` (berichtigt 19.09.2026).
+
+ Hier stand die alte Form -- und sie war grün, obwohl die Zeile
+ nichts tat: `zuschauer` hält Mengen, und eine Menge hat kein
+ `length`. Der Ausdruck war immer `undefined`, also immer falsch,
+ also wurde nie übersprungen: Wer die Seite offen hatte, bekam
+ zusätzlich eine Meldung aufs Handy.
+
+ Die Prüfung hat den alten Wortlaut bestätigt statt sein Verhalten.
+ Genau davor warnt die Hausregel vom 01.09.: Ein grüner Haken sagt
+ nur, dass die Bedingung erfüllt war -- nicht, dass sie das Richtige
+ geprüft hat. */
pruef("wer die Seite offen hat, bekommt KEINE zusätzliche Meldung",
- /if \(\(zuschauer\.get\(personId\) \|\| \[\]\)\.length\) continue;/.test(chat),
+ /\(zuschauer\.get\(personId\) \|\| new Set\(\)\)\.size\) continue;/.test(chat),
"sonst meldet es sich doppelt — der schnellste Weg, dass jemand alles abschaltet");
/* =====================================================================
@@ -161,5 +173,62 @@ pruef("Gegenprobe: ein festes Urgency würde auffallen",
pruef("Gegenprobe: eine gemeinsame Kennung würde auffallen",
!/tag:\s*istAnruf\s*\?\s*\("anruf-"/.test(' tag: d.art || "workspace",'));
+/* =====================================================================
+ 4. DER ZWEITE WEG — selbst nachfragen (19.09.2026)
+
+ Filipe: „wenn vanvan rangeht und redet klingelt es immer noch bei
+ mir weiter."
+
+ Im Protokoll nachgemessen: Sie WAR im Gespräch (24 Sekunden, mit
+ eigenem `anruf_ende`). Das Ereignis „dabei" wurde also verschickt
+ und kam beim Anrufer nicht an.
+
+ Geprüft und ausgeschlossen: Raumzugehörigkeit, Ereignis-Verkabelung,
+ Tonsteuerung, Service Worker. Es geht auf einem Weg verloren, der
+ von hier aus nicht messbar ist.
+
+ Deshalb wird die Ursache nicht weiter gesucht, sondern die
+ ABHÄNGIGKEIT beseitigt: Solange es klingelt, fragt der Anrufer
+ selbst nach. Der Ereignisstrom bleibt der schnellere erste Weg --
+ dies ist das Netz darunter.
+ ===================================================================== */
+console.log("\n --- Der zweite Weg ---");
+
+const anrufJs = lies("workspace/assets/js/anruf.js");
+
+pruef("der Anrufer fragt selbst nach, ob schon jemand dran ist",
+ /function nachfrageStarten\(raumId\)/.test(anrufJs),
+ "ohne das hängt ein klingelndes Telefon an einem einzigen Kanal");
+
+pruef("und zwar ab dem Moment des Wählens",
+ /klingelWache\(KLINGELT_MS\);[\s\S]{0,160}nachfrageStarten\(raumId\)/.test(anrufJs));
+
+pruef("sie hält an, sobald die Verbindung steht",
+ /if \(anruf\.beginn\) return nachfrageStoppen\(\)/.test(anrufJs));
+
+/* SIE MUSS AN JEDEM ENDE AUFHOEREN. Eine Schleife, die weiterläuft,
+ nachdem das Gespräch vorbei ist, fragt den Server alle zwei Sekunden
+ nach einem Anruf, den es nicht mehr gibt -- und das auf jedem Gerät,
+ das je telefoniert hat. */
+for (const [wo, muster] of [
+ ["beim Auflegen", /async function auflegen\(melden\) \{[\s\S]{0,160}nachfrageStoppen\(\)/],
+ ["wenn die Verbindung steht", /nachfrageStoppen\(\);\s*\/\/ und die Nachfrage/],
+ ["wenn das Ereignis doch ankommt", /d\.art === 'dabei'[\s\S]{0,260}nachfrageStoppen\(\)/],
+]) {
+ pruef(`die Nachfrage hört auf: ${wo}`, muster.test(anrufJs));
+}
+
+/* =====================================================================
+ 5. DAS PROTOKOLL MUSS DIE FRAGE BEANTWORTEN KOENNEN
+
+ Bis heute standen dort nur Anfang und Ende. Die wichtigste Frage bei
+ der Suche -- „ist sie ueberhaupt rangegangen?" -- war nur ueber
+ einen Umweg zu beantworten. Das ist eine Schlussfolgerung, keine
+ Auskunft.
+ ===================================================================== */
+pruef("das Rangehen steht im Protokoll",
+ /protokolliere\("anruf_dabei"/.test(lies("server/workspace-anruf.js")),
+ "sonst lässt sich später nicht sagen, OB jemand rangegangen ist");
+
console.log(`\n ${ok} bestanden, ${fehl} fehlgeschlagen\n`);
process.exit(fehl ? 1 : 0);
diff --git a/server/workspace-anruf.js b/server/workspace-anruf.js
index cbe115d8..64bf5789 100644
--- a/server/workspace-anruf.js
+++ b/server/workspace-anruf.js
@@ -496,6 +496,24 @@ anrufRouter.post("/workspace/api/anruf/:raum/dabei", gleicheHerkunft, (req, res)
person: { id: req.person.id, name: req.person.name },
wer: [...a.wer.entries()].map(([id, w]) => ({ id, name: w.name })),
}, [], "anruf");
+
+ /* DAS RANGEHEN GEHOERT INS PROTOKOLL (19.09.2026).
+
+ Bis heute standen dort nur `anruf_start` und `anruf_ende`. Bei
+ der Suche nach „es klingelt weiter, obwohl sie dran ist" war
+ damit die wichtigste Frage nicht zu beantworten: IST sie
+ ueberhaupt rangegangen?
+
+ Herauszufinden war es nur ueber einen Umweg -- `anruf_ende` mit
+ ihrer Personennummer. Das ist eine Schlussfolgerung, keine
+ Auskunft. Ein Protokoll, das den Anfang und das Ende kennt, aber
+ nicht den Moment dazwischen, laesst genau die Frage offen, die
+ man spaeter stellt. */
+ protokolliere("anruf_dabei", {
+ personId: req.person.id, rolle: req.person.rolle, ip: echteIp(req),
+ detail: `Raum ${raumId}, jetzt ${a.wer.size} dabei`,
+ });
+
res.json({ ok: true, video: a.video,
wer: [...a.wer.entries()].map(([id, w]) => ({ id, name: w.name })) });
} catch (f) {
diff --git a/server/workspace-chat.js b/server/workspace-chat.js
index fe6e24f8..f1e664d4 100644
--- a/server/workspace-chat.js
+++ b/server/workspace-chat.js
@@ -1879,7 +1879,20 @@ function chatEreignis(raumId, nachricht, benachrichtigen, art = "neu") {
Meldung aufs Handy zu schicken, ist der schnellste Weg, dass er
Benachrichtigungen abschaltet. */
for (const personId of benachrichtigen) {
- if ((zuschauer.get(personId) || []).length) continue;
+ /* `.size` UND NICHT `.length` (berichtigt 19.09.2026).
+
+ `zuschauer` haelt Mengen (`new Set()`), und eine Menge hat kein
+ `length` -- der Ausdruck war IMMER `undefined`, also immer
+ falsch, also wurde nie uebersprungen. Folge: Wer die Seite offen
+ hatte, bekam zusaetzlich zur Nachricht auf dem Bildschirm noch
+ eine Meldung aufs Handy.
+
+ Genau davor warnt der Kommentar drei Zeilen darueber: „der
+ schnellste Weg, dass er Benachrichtigungen abschaltet". Die
+ Absicht stand da, die Zeile tat das Gegenteil -- und `siehtZu()`
+ weiter unten macht es mit `.size` schon richtig. Gefunden beim
+ Nachverfolgen eines ganz anderen Fehlers. */
+ if ((zuschauer.get(personId) || new Set()).size) continue;
/* DIE ART GEHT MIT (18.09.2026). Sie stand als Parameter oben und
endete im Ereignisstrom -- die Benachrichtigung bekam sie nie zu
sehen und behandelte deshalb JEDES Ereignis als Chatnachricht.
diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html
index 062f023d..97439204 100644
--- a/workspace/anruf-probe.html
+++ b/workspace/anruf-probe.html
@@ -16,15 +16,15 @@
verdeckt. Gefunden hat es pruef-struktur.
Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. -->
-
-
+
+
-
+