From 26937dda1620626a4ca05108404ede2c718d9857 Mon Sep 17 00:00:00 2001 From: Dogfather Date: Sat, 19 Sep 2026 19:15:51 +0200 Subject: [PATCH] Ein klingelndes Telefon haengt nicht mehr an einem einzigen Kanal Filipe: "wenn vanvan rangeht und redet klingelt es immer noch bei mir weiter, der anruf verbindet nicht richtig." === WAS DAS PROTOKOLL SAGT === 17:04:52 anruf_start Person 1 (Filipe) 17:05:25 anruf_ende Person 4 (VanVan) 24 s 17:05:31 anruf_ende Person 1 (Filipe) 39 s Sie WAR im Gespraech -- der Server hat sie 24 Sekunden als Teilnehmerin gefuehrt. Das Ereignis "dabei" ist also verschickt worden. Bei Filipe kam es nicht an: `tonAus()` ist das Erste im `dabei`-Zweig, noch vor jeder Pruefung, und das Tuten lief weiter. === GEPRUEFT UND AUSGESCHLOSSEN === Raumzugehoerigkeit beide in Raum 1, bei keinem `raus_am` gesetzt Verkabelung Server sendet mit `art: "anruf"`, chat.js reicht an window.anrufEreignis weiter, anruf.js nimmt entgegen -- alle drei Stellen stimmen Tonsteuerung ein einziger Taktgeber, `tonAus` raeumt ihn; kein zweiter Weg, der ihn neu startet Ereignisstrom Keep-alive vorhanden, Kopfzeilen richtig (no-transform, X-Accel-Buffering: no) Service Worker hat gar keinen fetch-Handler, kann also kein altes Skript ausliefern teilnehmerVon vs. teilnehmerFuerAnruf reicht nur durch, dieselbe Abfrage Es geht unterwegs verloren, auf einem Weg, der von hier aus nicht messbar ist: Ereignisstrom ueber Cloudflare, ein schlafender Reiter, ein Neustart im falschen Moment. === ALSO NICHT WEITERSUCHEN, SONDERN DIE ABHAENGIGKEIT BESEITIGEN === Ein klingelndes Telefon darf nicht an einem einzigen, zerbrechlichen Kanal haengen. Solange es klingelt, fragt der Anrufer jetzt SELBST nach: "ist schon jemand dran?" -- alle zwei Sekunden an `/workspace/api/anruf/:raum`, das es laengst gibt. Der Ereignisstrom bleibt der erste Weg, er ist schneller. Das hier ist das Netz darunter. Kommt das Ereignis an, hat die Nachfrage nichts mehr zu tun und haelt von selbst an (sie prueft `anruf.beginn` und die bekannten Teilnehmer). Sie hoert an JEDEM Ende auf: beim Auflegen, wenn die Verbindung steht, wenn das Ereignis doch ankommt, wenn der Anruf vorbei ist. Eine Schleife, die weiterlaeuft, fragt sonst auf jedem Geraet, das je telefoniert hat, alle zwei Sekunden nach einem Anruf, den es nicht mehr gibt. Alle zwei Sekunden und nicht jede halbe: Es klingelt hoechstens zwei Minuten, das sind sechzig Abrufe. === ZWEI DINGE, DIE DIESE SUCHE ERST SO MUEHSAM GEMACHT HABEN === DAS PROTOKOLL KANNTE ANFANG UND ENDE, ABER NICHT DEN MOMENT DAZWISCHEN. Die wichtigste Frage -- "ist sie ueberhaupt rangegangen?" -- war nur ueber einen Umweg zu beantworten (ein `anruf_ende` mit ihrer Nummer). Das ist eine Schlussfolgerung, keine Auskunft. `anruf_dabei` steht jetzt drin, mit der Zahl der Beteiligten. UND EINE PRUEFUNG WAR GRUEN, OHNE ETWAS ZU PRUEFEN. In chatEreignis stand `(zuschauer.get(personId) || []).length` -- `zuschauer` haelt aber Mengen, und eine Menge hat kein `length`. Der Ausdruck war IMMER undefined, also immer falsch, also wurde nie uebersprungen: Wer die Seite offen hatte, bekam zusaetzlich zur Nachricht auf dem Bildschirm noch eine Meldung aufs Handy. Der Kommentar drei Zeilen darueber warnt woertlich davor ("der schnellste Weg, dass er Benachrichtigungen abschaltet"), und `siehtZu()` weiter unten macht es mit `.size` richtig. Die Absicht stand da, die Zeile tat das Gegenteil. Meine eigene Pruefung hat das mitgetragen: Sie bestaetigte den alten WORTLAUT statt sein VERHALTEN und war deshalb gruen. Genau die Hausregel vom 01.09. -- ein gruener Haken sagt nur, dass die Bedingung erfuellt war, nicht dass sie das Richtige geprueft hat. Jetzt prueft sie auf `.size`. GEMESSEN: pruef-anruf-klingelt 24/0 (vorher 17), pruef-anruf 114/0, pruef-turn-wege 15/0, pruef-meldungen 8/0. Co-Authored-By: Claude Opus 5 --- server/pruef-anruf-klingelt.mjs | 71 +++++++++++++++++++++++++- server/workspace-anruf.js | 18 +++++++ server/workspace-chat.js | 15 +++++- workspace/anruf-probe.html | 10 ++-- workspace/app.webmanifest | 8 +-- workspace/assets/js/anruf.js | 89 +++++++++++++++++++++++++++++++++ workspace/aufgaben.html | 26 +++++----- workspace/automation.html | 28 +++++------ workspace/befinden.html | 26 +++++----- workspace/bereich.html | 38 +++++++------- workspace/bewerben.html | 32 ++++++------ workspace/bewerbungen.html | 30 +++++------ workspace/calls.html | 30 +++++------ workspace/chat.html | 30 +++++------ workspace/content.html | 32 ++++++------ workspace/crew-index.html | 12 ++--- workspace/crew.webmanifest | 8 +-- workspace/dateien.html | 28 +++++------ workspace/entwicklung.html | 26 +++++----- workspace/hilfe.html | 24 ++++----- workspace/index.html | 10 ++-- workspace/kalender.html | 30 +++++------ workspace/leistung.html | 28 +++++------ workspace/personen.html | 28 +++++------ workspace/profil.html | 30 +++++------ workspace/rechte.html | 26 +++++----- workspace/report.html | 30 +++++------ workspace/scouting.html | 28 +++++------ workspace/start.html | 26 +++++----- workspace/startcheck.html | 30 +++++------ workspace/steckbrief.html | 30 +++++------ workspace/talente.html | 28 +++++------ workspace/team.html | 28 +++++------ workspace/teamlage.html | 26 +++++----- workspace/teilen.html | 24 ++++----- workspace/treff-moderation.html | 26 +++++----- workspace/treff-regeln.html | 28 +++++------ workspace/uebersicht.html | 28 +++++------ workspace/unsere-seiten.html | 24 ++++----- workspace/werdegang.html | 28 +++++------ workspace/wissen.html | 28 +++++------ 41 files changed, 667 insertions(+), 478 deletions(-) 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`. --> - - + + - +