From 2fb92f86f3e7b137b25c02f0713f24e4a97b26e5 Mon Sep 17 00:00:00 2001 From: Dogfather Date: Fri, 2 Oct 2026 19:25:54 +0200 Subject: [PATCH] Die Routenwache war unvollstaendig -- 13 Routen waren ihr unsichtbar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GEFUNDEN ALS FEHLALARM, GEBLIEBEN IST EIN ECHTER FUND. pruef-struktur meldete: assets/js/manager-ziele.js: Schnittstelle gibt es nicht -> /workspace/api/manager-ziele Nachgesehen statt geglaubt: Die Seite ruft diese Adresse NIE auf. In Zeile 31 steht `const BASIS = '/workspace/api/manager-ziele'`, benutzt wird ausschliesslich `${BASIS}/stand`, `${BASIS}/eintraege`, `${BASIS}/eintrag/${id}`. DER EIGENTLICHE FUND LAG EINE EBENE TIEFER. Der SERVER registriert seine Routen genauso: const BASIS = "/workspace/api/manager-ziele"; managerZieleRouter.get(`${BASIS}/stand`, ...) Die Sammelregel verlangte aber, dass ein Routenpfad direkt mit `/workspace/` beginnt. ALLE DREIZEHN Routen dieses Moduls fehlten damit in der Liste -- gemessen, nicht geschaetzt. Die Wache war also nicht zu streng, sie war UNVOLLSTAENDIG: Zu diesen Routen konnte sie gar nichts sagen, weder dass es sie gibt noch dass es sie nicht gibt. Und weil die Aufrufe dorthin ebenfalls zusammengesetzt sind, ist es nie aufgefallen -- ausser an dieser einen nackten Konstanten. Server-Routen eingelesen: 401 -> 414 GEAENDERT 1. Einfache Praefix-Konstanten werden je Datei aufgeloest. Mehr nicht: Wer seinen Pfad aus drei Variablen zusammensetzt, bleibt unauffindbar -- und das ist richtig so, denn geraten wird hier nicht. Ohne bekannten Wert wird GAR NICHTS eingetragen; eine geratene Route waere schlimmer als eine fehlende, weil sie einen toten Aufruf als lebendig durchgehen liesse. 2. Eine nackte Praefix-Konstante im Browser gilt als Praefix, wenn es Routen DARUNTER gibt. Abgeleitet, nicht aufgezaehlt -- eine Ausnahmeliste mit „manager-ziele" darin waere die naechste, die niemand pflegt. GEGENPROBEN IN BEIDE RICHTUNGEN, weil die neue Regel etwas durchlaesst: eine Praefix-Konstante wird als Praefix erkannt (Routen darunter) eine erfundene Adresse OHNE Routen darunter bleibt ein Fund und eine echte Route bleibt eine echte Route, kein Praefix DAZU VIER SCHLUSSZEICHEN. Die Wache fuer das deutsche Anfuehrungszeichen meldete vier Stellen in denselben zwei Dateien: `„${was}" löschen?` und drei Geschwister. Berichtigt auf `“`. UND EINE KORREKTUR AN MIR: Ich habe pruef-struktur heute dreimal als „99 ok, Exitcode 0" protokolliert und dabei zwei rote Zeilen uebersehen -- mein Filter zeigte nur die ersten drei FEHL-Zeilen und die Zahl der gruenen. Gefunden habe ich es erst, als dieselbe Pruefung spaeter Exitcode 1 meldete. Nachgemessen mit `git stash`: Die zwei Funde stecken auch in HEAD, sie sind also nicht aus meiner laufenden Arbeit gekommen. Eine Zusammenfassung, die nur die gruenen Zeilen zaehlt, ist keine. GEPRUEFT: pruef-struktur 102 ok, 0 Fehler. Co-Authored-By: Claude Opus 5 --- server/pruef-struktur.mjs | 92 +++++++++++++++++++++++++++- server/workspace-manager-ziele.js | 2 +- workspace/assets/js/manager-ziele.js | 6 +- 3 files changed, 94 insertions(+), 6 deletions(-) diff --git a/server/pruef-struktur.mjs b/server/pruef-struktur.mjs index 5b1f57ce..3011708b 100644 --- a/server/pruef-struktur.mjs +++ b/server/pruef-struktur.mjs @@ -84,9 +84,50 @@ for (const datei of serverDateien) { Die Erfassung der AUFRUFE kannte alle drei Zeichen schon (["'`]) -- nur die Erfassung der ROUTEN nicht. Zwei Regeln fuer dieselbe Frage, und eine davon war aelter. */ + /* ==== AUCH ROUTEN HINTER EINER KONSTANTEN (02.10.2026) ========= + + Gemeldet wurde „Schnittstelle gibt es nicht -> + /workspace/api/manager-ziele". Nachgesehen statt geglaubt: Die + Adresse wird nie aufgerufen; sie ist eine Konstante, und benutzt + wird `${BASIS}/stand`, `${BASIS}/eintraege` und acht weitere. + + DER EIGENTLICHE FUND LAG EINE EBENE TIEFER: Der SERVER + registriert sie genauso -- + + const BASIS = "/workspace/api/manager-ziele"; + managerZieleRouter.get(`${BASIS}/stand`, ...) + + -- und die Sammelregel hier verlangte, dass der Pfad direkt mit + `/workspace/` beginnt. ALLE ZEHN Routen dieses Moduls fehlten + damit in der Liste. Die Wache war nicht zu streng, sie war + unvollstaendig: Sie konnte zu diesen Routen gar nichts sagen -- + weder dass es sie gibt, noch dass es sie nicht gibt. + + Jetzt werden einfache Praefix-Konstanten je Datei aufgeloest. + Mehr nicht: Wer seinen Pfad aus drei Variablen zusammensetzt, + bleibt unauffindbar -- und das ist richtig so, denn geraten wird + hier nicht. */ + const konstanten = new Map(); + for (const k of text.matchAll( + /\bconst\s+([A-Za-z_$][\w$]*)\s*=\s*["'`](\/workspace\/[^"'`]*)["'`]\s*;/g)) { + konstanten.set(k[1], k[2]); + } const treffer = text.matchAll( - /Router\.(get|post|patch|put|delete|use)\(\s*\n?\s*["'`](\/workspace\/[^"'`]*)/g); - for (const t of treffer) ROUTEN.push({ art: t[1], pfad: t[2], datei }); + /Router\.(get|post|patch|put|delete|use)\(\s*\n?\s*["'`](\$\{[A-Za-z_$][\w$]*\})?(\/workspace\/[^"'`]*|\/[^"'`]*)/g); + for (const t of treffer) { + let pfad = t[3]; + if (t[2]) { + const name = t[2].slice(2, -1); + const wert = konstanten.get(name); + /* OHNE BEKANNTEN WERT WIRD NICHTS EINGETRAGEN. Eine geratene + Route waere schlimmer als eine fehlende: Sie liesse einen + toten Aufruf als lebendig durchgehen. */ + if (!wert) continue; + pfad = wert + pfad; + } + if (!pfad.startsWith("/workspace/")) continue; + ROUTEN.push({ art: t[1], pfad, datei }); + } } ok(ROUTEN.length >= 80, `${ROUTEN.length} Server-Routen eingelesen`); @@ -209,6 +250,37 @@ for (const name of [...jsDateien.map((n) => "assets/js/" + n), ...seiten]) { } continue; } + /* ==== EINE PRAEFIX-KONSTANTE IST KEIN AUFRUF (02.10.2026) ===== + + Gemeldet wurde: + + assets/js/manager-ziele.js: Schnittstelle gibt es nicht + -> /workspace/api/manager-ziele + + Nachgesehen statt geglaubt: Die Seite ruft diese Adresse NIE + auf. In Zeile 31 steht + + const BASIS = '/workspace/api/manager-ziele'; + + und benutzt wird sie ausschliesslich als `${BASIS}/stand`, + `${BASIS}/eintraege`, `${BASIS}/eintrag/${id}` -- zehn Routen + gibt es darunter, alle vorhanden. + + Der Zweig darueber faengt nur Praefixe mit Schraegstrich am + Ende ab. Eine Konstante ohne Schraegstrich fiel durch und wurde + als fehlende Schnittstelle gemeldet. Ein Fehlalarm, der bei + jedem Lauf kommt -- und eine Warnung, die immer kommt, nimmt + irgendwann die echte mit. + + DIE REGEL IST ABGELEITET, NICHT AUFGEZAEHLT: Gibt es unter + diesem Pfad Routen, aber keine EXAKT darauf, dann ist es ein + Praefix. Eine Ausnahmeliste mit „manager-ziele" darin waere die + naechste, die niemand pflegt. */ + if (!routeGibtEs(roh) + && ROUTEN.some((r) => r.art !== "use" && r.pfad.startsWith(roh + "/"))) { + nurPraefix++; + continue; + } geprueftApi++; if (!routeGibtEs(roh)) ok(false, `${name}: Schnittstelle gibt es nicht -> ${roh}`); } @@ -1443,6 +1515,22 @@ ok(routeGibtEs("/workspace/api/aufgaben"), ok(!existsSync(join(WS, "gibtesnicht.html")), "erfundene Seite wird als fehlend erkannt"); +/* DIE NEUE PRAEFIX-REGEL IN BEIDE RICHTUNGEN (02.10.2026). + + Sie laesst etwas durch -- also muss nachgewiesen sein, dass sie + nicht ALLES durchlaesst. Sonst waere aus einer Wache eine + Freigabestelle geworden. */ +{ + const istPraefix = (p) => !routeGibtEs(p) + && ROUTEN.some((r) => r.art !== "use" && r.pfad.startsWith(p + "/")); + ok(istPraefix("/workspace/api/manager-ziele"), + "eine Praefix-Konstante wird als Praefix erkannt (Routen darunter)"); + ok(!istPraefix("/workspace/api/gibtesnicht"), + " eine erfundene Adresse OHNE Routen darunter bleibt ein Fund"); + ok(!istPraefix("/workspace/api/aufgaben"), + " und eine echte Route bleibt eine echte Route, kein Praefix"); +} + /* ===================================================================== RUFT JEMAND `openssl` WIEDER DIREKT AUF? diff --git a/server/workspace-manager-ziele.js b/server/workspace-manager-ziele.js index d384827c..7893c6bf 100644 --- a/server/workspace-manager-ziele.js +++ b/server/workspace-manager-ziele.js @@ -756,7 +756,7 @@ function eintragAnlegen(person, rumpf, monat, heute) { return { fehler: "schon_eingetragen", text: w.name - ? `„${w.name}" steht diesen Monat schon in deiner Liste.` + ? `„${w.name}“ steht diesen Monat schon in deiner Liste.` : "Dieses Video steht diesen Monat schon in deiner Liste.", }; } diff --git a/workspace/assets/js/manager-ziele.js b/workspace/assets/js/manager-ziele.js index 8c342bf1..bd248bc4 100644 --- a/workspace/assets/js/manager-ziele.js +++ b/workspace/assets/js/manager-ziele.js @@ -661,12 +661,12 @@ const was = e.name || (e.link ? kurzLink(e.link) : tagText(e.datum)); const frage = window.frageNach ? await window.frageNach({ - titel: `„${was}" löschen?`, + titel: `„${was}“ löschen?`, was: 'Der Eintrag verschwindet aus deinem Monatszähler.', bleibt: e.lead_id ? 'Der Lead im Scout-CRM bleibt bestehen.' : '', endgueltig: true, ja: 'Löschen', }) - : window.confirm(`„${was}" löschen?`); + : window.confirm(`„${was}“ löschen?`); if (!frage) return; try { const a = await hole(`${BASIS}/eintrag/${e.id}`, { method: 'DELETE' }); @@ -1128,7 +1128,7 @@ platz.append(tabelle); platz.append(el('p', 'mz-ziele__gilt', `${leute.length} von ${d.leute.length} Personen · sortiert nach ` - + `„${spaltenName(teamSortierung.spalte, d)}"`)); + + `„${spaltenName(teamSortierung.spalte, d)}“`)); } catch { $('team').textContent = ''; $('team').append(el('p', 'mz-leer', 'Die Übersicht konnte nicht geladen werden.'));