Ein Zeitraum geht jetzt durch -- als Zeitraum, nicht als Tag

Filipe: "verbesser das, also ich will dass das auch so geht, mach dass
es funktioniert, ich will es so einfach und perfekt wie moeglich. also
sieh zu dass die excel auch so durch geht."

Backstage gibt eine Ausgabe fuer einen ZEITRAUM heraus --
"2026-09-01 ~ 2026-09-13", eine Zeile je Creator, alle Zahlen
aufsummiert. Am Vormittag wurde so eine Zeile abgewiesen. Jetzt geht
sie durch.

DREI WEGE WAEREN MOEGLICH GEWESEN, ZWEI DAVON WAEREN
ZAHLENFAELSCHUNG:
  * auf den ersten Tag schreiben -> dreizehn Tage auf einem Tag; die
    Zahl steht da, sie ist gross, sie sieht richtig aus, und niemand
    kann spaeter sagen, was darin steckt;
  * gleichmaessig verteilen -> erfundene Tage, die es nie gab.
Der dritte ist dieser: den Zeitraum ALS Zeitraum ablegen. Was drinsteht,
ist dann wahr -- und was er nicht sagt (welcher Tag wie lief),
behauptet er auch nicht.

EIGENE TABELLE UND NICHT EIN FELD IN `leistung`: Dort ist der
Schluessel (creator, tag). Ein Zeitraum ab dem 1. September wuerde mit
dem ECHTEN 1. September zusammenstossen, und eine der beiden Zahlen
waere weg. Getrennt kann keines das andere ueberschreiben -- und die
Wochenzahlen bleiben, was sie sind: aus Tagen gerechnet.

Der Schluessel ist (creator, von, bis): Dieselbe Datei zweimal
einzulesen ersetzt denselben Zeitraum, statt ihn zu verdoppeln.

AUF DER SEITE steht ein eigener Block zwischen Woche und Tageszeilen:
die Spanne vorn, die Zahl der Tage als Marke daneben, die Werte
darunter. Dazu EINE Umrechnung, und nur diese: "Ø 4.129 Diamanten pro
Tag" -- als Durchschnitt bezeichnet, nirgends gespeichert. Wer eine
Woche vergleichen will, braucht sie; wer sie fuer einen echten Tag
haelt, hat das Wort nicht gelesen. Darueber steht woertlich, dass diese
Zahlen nicht in die Wochenzahlen eingehen.

MIT DER ECHTEN DATEI GEMESSEN: alle 8 Zeilen gehen durch, 8 als
Zeitraum, 0 abgelehnt. Spanne 01.09.-11.09. = 11 Tage, Diamanten
53.679, Dauer 5171 Minuten.

pruef-backstage-import 86 -> 106. Die Pruefung, auf die es ankommt, ist
nicht "es wird gespeichert", sondern "es wird NICHT in die Woche
gemischt": kein Tag kommt hinzu, die Wochenzahl bleibt Ziffer fuer
Ziffer dieselbe. Dazu die Gegenprobe, dass ein Zeitraum von EINEM Tag
weiterhin ein Tag bleibt -- sonst hiesse alles andere nur, dass jetzt
alles als Zeitraum abgelegt wird.

DREI PRUEFUNGEN GEDREHT, KEINE GELOESCHT: Zwei behaupteten noch die
Ablehnung vom Vormittag. Und tagAusZelle() hat jetzt DREI Ausgaenge
statt zwei (Tag, Zeitraum, Grund) -- geprueft wird, dass nie zwei davon
gleichzeitig kommen. Gaebe es zwei, entschiede jeder Aufrufer selbst,
was Vorrang hat, und der zweite entschiede anders als der erste. Genau
daran ist heute frueh der Zeitraum-Schutz gescheitert.

ZWEI EIGENE MESSFEHLER, beide von der Pruefung gefunden: Ich verlangte
"kein einziger Tag in der Spanne" und uebersah, dass weiter oben schon
ein Tag geschrieben worden war, der hineinfaellt -- gemessen wird jetzt
die VERAENDERUNG. Und ich mass den Zeitraum-Block, waehrend ein anderer
Creator geoeffnet war: keine Frage an die Seite, sondern an die falsche
Person.

Nebenbei zum zweiten Mal heute: eine Versalzeile mit 10,88 px. Auf
.72rem angehoben, bevor pruef-css-klassen sie findet.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-14 16:23:16 +02:00
co-authored by Claude Opus 5
parent 0207b05da6
commit e82bf45f0d
35 changed files with 829 additions and 367 deletions
+168 -5
View File
@@ -337,6 +337,121 @@ for (const [rolle, code, wer] of [
`der Scout sieht seinen Creator in der Liste (${namen || "leer"})`);
}
{
/* ---- EIN ZEITRAUM GEHT JETZT DURCH (14.09.2026) ------------------
Filipe: "ich will dass das auch so geht, mach dass es
funktioniert ... sieh zu dass die excel auch so durch geht."
Am Vormittag wurde eine Zeile mit "2026-09-01 ~ 2026-09-13"
abgewiesen -- richtig, denn auf einen Tag geschrieben waeren es
dreizehn Tage auf einmal gewesen. Jetzt geht sie durch, aber als
ZEITRAUM: eigene Tabelle, eigener Block auf der Seite, und die
Wochenzahlen bleiben unberuehrt.
DAS IST DIE PRUEFUNG, AUF DIE ES ANKOMMT: nicht "es wird
gespeichert", sondern "es wird NICHT in die Woche gemischt". Eine
Summe aus dreizehn Tagen in einer Wochenzahl waere genau der
stille Fehler, den das Ganze vermeiden soll. */
const spanneText = [
"Datenzeitraum\tCreator\tDiamanten\tLIVE-Dauer\tGültige LIVE-Gehen-Tage",
"2026-09-01 ~ 2026-09-13\t@Nova_Live\t53.679\t86Std. 10Min. 52Sek.\t11",
].join("\n");
{
const v = await ruf("/workspace/api/leistung/netzwerk-import/vorschau",
keksDogi, { text: spanneText });
ok(v.status === 200, `die Vorschau nimmt den Zeitraum an (HTTP ${v.status})`);
ok(v.daten?.zeitraeume === 1,
`sie zaehlt ihn als Zeitraum, nicht als Tag (${v.daten?.zeitraeume})`);
ok(v.daten?.spanne?.tage === 13,
`und nennt die Zahl der Tage (${v.daten?.spanne?.tage})`);
ok((v.daten?.probleme || []).length === 0,
`keine Absage mehr (${(v.daten?.probleme || []).length} Probleme)`);
}
/* Die Woche VOR dem Import -- als Vergleichspunkt. Ohne ihn hiesse
"die Woche stimmt" nur, dass irgendetwas dasteht. */
const wocheVor = await (await fetch(BASIS + `/workspace/api/leistung/${idNova}`,
{ headers: { Cookie: keksDogi } })).json();
const diaVor = wocheVor?.woche?.diamanten?.wert ?? null;
/* WIE VIELE TAGESZEILEN ES SCHON GIBT. Der erste Entwurf verlangte
hier NULL -- und uebersah, dass die Backstage-Tabelle weiter oben
bereits einen Tag geschrieben hat, der in dieselbe Spanne faellt.
Die Pruefung war rot, der Code richtig. Gemessen wird deshalb die
VERAENDERUNG, nicht der Absolutwert. */
const tageVor = (() => {
const d0 = new DatabaseSync(DB, { readOnly: true });
const n = d0.prepare(
"SELECT COUNT(*) AS n FROM leistung WHERE creator_id = ? AND tag >= '2026-09-01' AND tag <= '2026-09-13'")
.get(idNova).n;
d0.close();
return n;
})();
{
const s = await ruf("/workspace/api/leistung/netzwerk-import",
keksDogi, { text: spanneText });
ok(s.status === 200, `der Zeitraum wird uebernommen (HTTP ${s.status})`);
ok(s.daten?.zeitraeume === 1 && s.daten?.geschrieben === 0,
`als Zeitraum geschrieben, nicht als Tag (${s.daten?.zeitraeume} / ${s.daten?.geschrieben})`);
}
{
const d2 = new DatabaseSync(DB, { readOnly: true });
const z = d2.prepare(
"SELECT * FROM leistung_zeitraum WHERE creator_id = ?").get(idNova);
const tage = d2.prepare(
"SELECT COUNT(*) AS n FROM leistung WHERE creator_id = ? AND tag >= '2026-09-01' AND tag <= '2026-09-13'")
.get(idNova).n;
d2.close();
ok(z && z.von === "2026-09-01" && z.bis === "2026-09-13" && z.tage === 13,
`er steht in der Datenbank (${z?.von} bis ${z?.bis}, ${z?.tage} Tage)`);
ok(z?.diamanten === 53679, `mit den Diamanten (${z?.diamanten})`);
ok(z?.dauer_min === 5171, `und der Dauer in Minuten (${z?.dauer_min})`);
/* DER WICHTIGSTE HAKEN: In der TAGES-Tabelle steht davon nichts. */
ok(tage === tageVor,
`und KEIN einziger Tag kam hinzu (${tageVor} -> ${tage} Tageszeilen)`);
}
{
/* Und die Wochenzahl ist unveraendert -- der Zeitraum mischt sich
nicht hinein. */
const nach = await (await fetch(BASIS + `/workspace/api/leistung/${idNova}`,
{ headers: { Cookie: keksDogi } })).json();
ok((nach?.woche?.diamanten?.wert ?? null) === diaVor,
`die Wochenzahl bleibt unveraendert (${diaVor} -> ${nach?.woche?.diamanten?.wert})`);
ok(Array.isArray(nach?.zeitraeume) && nach.zeitraeume.length === 1,
`aber der Zeitraum wird mitgeliefert (${(nach?.zeitraeume || []).length})`);
}
{
/* DIESELBE DATEI ZWEIMAL ersetzt denselben Zeitraum, statt ihn zu
verdoppeln -- sonst stuenden nach dem zweiten Einlesen zwei
gleiche Karten da. */
await ruf("/workspace/api/leistung/netzwerk-import", keksDogi, { text: spanneText });
const d3 = new DatabaseSync(DB, { readOnly: true });
const n = d3.prepare(
"SELECT COUNT(*) AS n FROM leistung_zeitraum WHERE creator_id = ?").get(idNova).n;
d3.close();
ok(n === 1, `zweimal einlesen ergibt EINEN Zeitraum (${n})`);
}
{
/* GEGENPROBE: Ein Zeitraum von EINEM Tag ist kein Zeitraum -- er
geht weiterhin in die Tagestabelle. Ohne sie hiesse alles oben
nur, dass jetzt alles als Zeitraum abgelegt wird. */
const einTag = [
"Datenzeitraum\tCreator\tDiamanten",
`${gestern} ~ ${gestern}\t@Nova_Live\t1.234`,
].join("\n");
const s = await ruf("/workspace/api/leistung/netzwerk-import", keksDogi, { text: einTag });
ok(s.daten?.geschrieben === 1 && (s.daten?.zeitraeume ?? 0) === 0,
`ein Ein-Tages-Zeitraum bleibt ein Tag (${s.daten?.geschrieben} Tag, `
+ `${s.daten?.zeitraeume} Zeitraeume)`);
}
}
/* =======================================================================
7. Und die Seite selbst
======================================================================= */
@@ -504,16 +619,64 @@ console.log("\n=== Die Seite ===");
await seite.waitForTimeout(1800);
const spanne = await seite.evaluate(() =>
document.getElementById("netz-vorschau")?.textContent || "");
ok(spanne.includes("mehrere Tage") && spanne.includes("2026-09-01"),
`ein Zeitraum ueber mehrere Tage wird abgelehnt und BEGRUENDET ("${spanne.slice(0, 90)}…")`);
ok(!/1 von 1 Zeilen zugeordnet/.test(spanne),
"und die Zeile wird NICHT als zugeordnet gezaehlt");
/* GEDREHT AM 14.09.2026 NACHMITTAG, NICHT GELOESCHT.
Hier stand: "ein Zeitraum ueber mehrere Tage wird abgelehnt und
BEGRUENDET" -- richtig, bis Filipe sagte: "ich will dass das auch
so geht." Jetzt geht die Zeile durch, und die Vorschau sagt, dass
es ein ZEITRAUM ist. Eine geloeschte Pruefung senkt die Zahl und
beweist nichts; eine gedrehte haelt fest, dass die Aenderung eine
Entscheidung war. */
ok(/1 von 1 Zeilen zugeordnet/.test(spanne),
`ein Zeitraum ueber mehrere Tage geht jetzt durch ("${spanne.slice(0, 60)}…")`);
ok(!/mehrere Tage auf einmal/.test(spanne),
"und wird nicht mehr abgewiesen");
if (process.env.SCHIRM) {
await seite.locator("#netz-dialog").screenshot(
{ path: join(HIER, "pruef-netz-zeitraum.png") });
}
await seite.click("#netz-zu");
/* ---- UND WIE ES DANACH AUSSIEHT (14.09.2026) --------------------
Der Block mit den Zeitraeumen ist die eigentliche Antwort auf
"sieh zu dass die excel auch so durch geht": Die Zahlen sind da,
und man sieht auf einen Blick, worauf sie sich beziehen. */
await seite.click("#netz-los");
await seite.waitForTimeout(1800);
/* AUF DEN RICHTIGEN CREATOR SCHALTEN. Der erste Entwurf mass sofort
und fand nichts -- geoeffnet war Kiro, der Zeitraum gehoert Nova.
Das war kein Befund, sondern eine Frage an die falsche Person. */
await seite.selectOption("#creator", String(idNova)).catch(() => {});
await seite.waitForTimeout(1600);
const werOffen = await seite.evaluate(() =>
document.getElementById("creator")?.selectedOptions?.[0]?.textContent || "");
ok(/Nova/.test(werOffen), `Nova ist geoeffnet ("${werOffen.slice(0, 30)}")`);
const spannenBild = await seite.evaluate(() => ({
sichtbar: document.getElementById("spannen-block")?.hidden === false,
karten: document.querySelectorAll(".spanne").length,
zeit: document.querySelector(".spanne__zeit")?.textContent || "",
tage: document.querySelector(".spanne__tage")?.textContent || "",
schnitt: document.querySelector(".spanne__schnitt")?.textContent || "",
satz: document.querySelector(".spannen__satz")?.textContent || "",
}));
ok(spannenBild.sichtbar && spannenBild.karten >= 1,
`der Zeitraum-Block steht auf der Seite (${spannenBild.karten} Karten)`);
ok(spannenBild.zeit.includes("01.09.") && spannenBild.zeit.includes("13.09."),
`mit der Spanne davor ("${spannenBild.zeit}")`);
ok(/Tage/.test(spannenBild.tage),
`und der Zahl der Tage ("${spannenBild.tage}")`);
ok(/Ø/.test(spannenBild.schnitt) && /pro Tag/.test(spannenBild.schnitt),
`der Schnitt steht als Durchschnitt da, nicht als Tageswert ("${spannenBild.schnitt}")`);
ok(/nicht für einen Tag/.test(spannenBild.satz),
"und darueber steht, dass es kein Tageswert ist");
if (process.env.SCHIRM) {
await seite.locator("#spannen-block").screenshot(
{ path: join(HIER, "pruef-spannen.png") });
}
await seite.click("#netz-zu").catch(() => {});
await seite.waitForTimeout(300);
/* Gemessen wird SATZ FUER SATZ, nicht der Block. Ein Block, der
als Ganzes erscheint, erklaert einem Scout auch den Knopf, den er