/calendar — Kalender
Hinweis: Rahmen: 00-rahmen.md. Code:
packages/plugins/src/calendar/· Nachweisnpm run verify:kalender.
Wofür
Der Uhrenraum. Denotato schreibt in vier eigene Google-Kalender — Geburtstage, Prüfungen, Ereignisse, Fälliges — und der Abgleich ist vollständig: verschoben heißt verschoben, gelöscht heißt gelöscht.
Eine Prüfung bringt seit dem 26.09.2026 bis zu drei Termine (BE38, N314): ihren Termin und, wo unter /study eingetragen, „Anmeldeschluss: …" und „Rücktrittsfrist: …", ganztägig am Tag der Frist in der Zone des Kontos. Die Fristen tragen keine Art, sondern die Quelle pruefung und die Ausprägung feld:anmeldung_bis bzw. feld:ruecktritt_bis; sie führen in life.calendar_entries Buch und gehen über die Kategorie hinaus, die eine Regel auf die Quelle pruefung trifft (ZEITFELDER.pruefung kennt alle drei Felder). Aus der Prüfungsordnung abgeleitete Fristen gibt es erst mit C60.
Dieser Schirm ist die Bedienung dazu, die bis zum 09.09.2026 fehlte: gebaut war alles, zu erreichen war es nur über npm run kalender.
Die Vorschau zeigt Denotatos eigene Daten, nicht Googles. Sie beantwortet damit die Frage, die man vor einem Abgleich hat — was würde jetzt geschrieben? — und steht auch ohne verbundenes Konto da.
Heute ist der Tag des Kontos (N167). Seit dem 24.09.2026 gilt das auch für das Fenster der Vorschau, das Fenster jeder Kategorie und den Boden der Stundenplanserien ohne Anfang (F93). Vorher kam dieser Tag aus toISOString(), also in UTC, und zwischen Mitternacht und zwei Uhr begann „Termine in 7 Tagen" gestern.
Stundenplanserien enden am Vorlesungsende (VA13, N508, 04.10.2026). Trägt eine Veranstaltung kein „Gilt ab“ oder „Gilt bis“, füllt der Sammler die fehlende Grenze aus der Vorlesungszeit, in der der Tag liegt (sonst der nächsten): zuerst aus den eigenen Semestern im Studium mit Beginn und Ende, sonst aus der Vorgabe der Hochschule (verwaltung.md). Ein Zweiwochentakt ohne „Gilt ab“ bekommt nur das Ende, weil sein Takt am Anfang hängt. Der Boden der Serien ist der Montag des laufenden Semesterbeginns, sonst der heutige Montag; so bleibt DTSTART ein Semester lang stehen, statt jede Woche zu wandern. Ohne bekanntes Semester bleibt alles wie zuvor. Formular und Raster des Stundenplans zeigen weiter nur, was eingetragen ist.
Weg und Rahmen
| Route | /calendar (das Blatt) · /calendar/einrichten (die Einrichtung, seit 09.10.2026) |
| Merkmal | EVENTS |
| Zimmer | Uhrenraum · Lautstärke 3 · #7f8cf5 |
Was man sieht
Das Blatt und die Einrichtung (seit 09.10.2026, W-261009-kalender-einrichtung)
/calendar zeigt nur noch, was man beim Nachsehen braucht: das Anlegefach „Termin · Veranstaltung“ (bis 15.10.2026 „Termin“), „Meine Woche“ mit Legende und Blatt und die Einzelheiten eines Termins. Seit dem 14.10.2026 (KN-261014-woche-bild, Befund B2 der Kernprüfung) steht die Woche gleich unter dem Kopf: Das Vorlagenangebot steht über dem Bogen der Einrichtung, und der Kasten „Der Abgleich ist aus“ ist vom Blatt weg — den Zustand sagen die Zeile des Abgleichs und der Kasten unter „Was geschrieben wird“. Am Telefon beginnt das Blatt mit dem Tag, am Rechner mit der Woche; eine einmal gewählte Ansicht merkt sich das Gerät. Die sieben Abschnitte zum Einrichten — Abonnierte Kalender, Verbindungen (mit Abgleichbericht und den Knöpfen des Abgleichs; seit dem 15.10.2026 nach den Abos, KN-261015-abo-zuerst), Kategorien, Zuordnung, Fremde Kalender, Nach draußen und Was geschrieben wird (mit Vorlauf, Erinnerung und Fälliges-Modus) — stehen in dieser Reihenfolge auf dem eigenen Schirm „Kalender einrichten“ unter /calendar/einrichten, in einem Raum entsprechend unter /studium/calendar/einrichten. Vorher standen sie unter dem Blatt, und wer seine Woche sehen wollte, scrollte an sieben Abschnitten Bedienung vorbei, die er selten braucht.
Hin führt der Knopf Einrichten (Zeichen hebel) im Kopf des Kalenders, zurück Zum Kalender im Kopf der Einrichtung. Beide Schirme laden ihren Stand über denselben Haken (useKalenderdaten.ts) und teilen sich den letzten Stand im Gerät (L03); die ersten Fragen der Unterteile (B70) stellt nur die Einrichtung. Die Rückkehr von Google (?verbunden=, ?fehler=) und das Ziel eines neuen Abonnements führen seitdem auf /calendar/einrichten, weil dort der Satz dazu steht.
Ein Klick auf eine eigene Kategorie der Legende öffnet ein kleines Menü: Ausblenden bzw. Einblenden wie bisher und Bearbeiten. „Bearbeiten“ führt auf /calendar/einrichten?kategorie=<Kennung>; die Einrichtung schlägt die Kategorie in der Verwaltung zum Ändern auf, rollt zu ihr, setzt den Fokus in den Namen und nimmt den Parameter aus der Adresse. Im Rückfall auf die festen Arten gibt es nichts zu bearbeiten; dort schaltet der Klick wie vorher sofort.
Zuerst der Bogen, dann „Von Hand“ (seit 15.10.2026, S-261014-kalender-gemeinsam)
Christian wählte am 15.10.2026 im Musterbogen docs/gestaltung/musterboegen/kalender-einrichten-begleiter.html (K1 A, K2 A, K3 A, K4 C): Die Seite ist der Bogen. Ohne Parameter zeigt /calendar/einrichten (Einrichtungsbogen.tsx) den Stand in Sätzen auf Karton, je Bereich eine Zeile mit Ändern:
| Zeile | Satz | „Ändern“ führt auf |
|---|---|---|
| Abonnierte Kalender (seit 15.10.2026 die erste, KN-261015-abo-zuerst) | die Namen der Abos oder „Noch keiner“; ohne Abo heißt der Verweis Abonnieren | ?funktion=abonnieren |
| Abgleich | „Verbunden: …“ oder „Noch nicht verbunden“ · „Abgleich ist an/aus“ | ?funktion=verbinden |
| Farben | Zahl der Kategorien oder „Noch keine Kategorien“ | ?funktion=kategorien |
| Tagesrhythmus | je Gruppe gleicher Tage „Mo–Fr: auf um 07:00, 45 Minuten fertigmachen, schlafen um 23:30“, sonst „Noch nichts festgelegt“ | den Fragebogen bei „Wie sieht eine Uni-Woche aus?“ |
| Wege | je Weg „Zuhause nach Campus mit dem Rad: 20 Minuten“ und der Puffer, sonst „Noch keine Wege“ | den Fragebogen bei „Wie kommst du hin?“ |
Darunter Gemeinsam einrichten (Hauptknopf) und der Verweis Von Hand: alle Regeln und Einstellungen (?funktion=erweitert, der ganze Schirm von vorher mit allen sieben Abschnitten). Die Kacheln von S-261013-kalender-einrichten sind darin aufgegangen; ihre Funktionen (?funktion=verbinden, abonnieren, teilen, kategorien, inhalt) bleiben als Ziele der Zeilen und des Vorschlags. In jeder Funktion steht im Kopf neben Zum Kalender der Knopf Übersicht (Zeichen kacheln) zurück zum Bogen.
Der Fragebogen stellt eine Frage zur Zeit, Punkte zeigen den Fortschritt, Zurück steht auf jeder Frage, auf der ersten heißt er Abbrechen:
- Was soll dein Kalender für dich tun? — Abgleichen, Aufstehen/ Fertigmachen/Schlafen einplanen, „Sagen, wann ich losmuss“.
- Welche Kalender hast du? — Google, iCloud, über eine Adresse, im Telefon sehen.
- Wie sieht eine Uni-Woche aus? — Tage, Aufstehen, Fertigmachen, Schlafen, erste Veranstaltung. Nur, wenn der Tag oder die Wege gewählt sind.
- Wie kommst du hin? — Ziel, Verkehrsmittel (zu Fuß, Rad, Roller, Bus oder Bahn, Auto), Minuten Tür zu Tür, Puffer. Nur, wenn die Wege gewählt sind.
Danach folgen Rückfragen, je eine nur, wenn die Antworten sie brauchen; sie stehen fest, sobald man die letzte feste Frage verlässt, und die Punkte zählen sie mit:
- Und an den übrigen Tagen? — wenn die Uni-Woche nicht alle Tage hat; nennt die Tage und fragt wahlweise Aufstehen und Schlafen dort.
- Fährt dein Bus oder deine Bahn nach Fahrplan? — bei Bus oder Bahn, oder wenn schon ein Takt steht; Takt und eine Abfahrtsminute.
- Wie schaffst du es morgens? — wenn man erst nach der Losfahrzeit fertig wäre. Sagt beide Uhrzeiten und bietet „Früher aufstehen, um …“, „Schneller fertig werden, in … Minuten“ und „So lassen“.
Welche Rückfragen kommen (seit 16.10.2026, R1): Die Regeln nennen, welche in Frage kommen; beim Verlassen der letzten festen Frage fragt der Bogen den Begleiter (Anlass „Rückfragen beim Kalender einrichten“, nur wenn mindestens eine in Frage kommt). Das Modell wählt daraus und schreibt je einen Satz, warum; der Satz steht als Hinweis unter der Rückfrage. Eine Rückfrage, die die Regeln nicht zulassen, kann es nicht stellen. Mit geht, was der Bogen gefragt hat, ohne den Namen des Ziels. Ohne Modell, Schlüssel oder Budget kommen alle passenden Rückfragen, wie vorher. Solange gewählt wird, sagt der Knopf „Wählt Rückfragen …“; wer zurück- und wieder vorgeht, ohne etwas zu ändern, wird nicht noch einmal gefragt. Vorbelegt ist der Bogen mit dem, was schon eingestellt ist.
Die freie Rückfrage (seit 16.10.2026, R1, zweiter Teil): Zugleich stuft ein eigener Anlass („Freie Rückfrage beim Kalender einrichten“, dem ein Admin ein kleines Modell zuweisen kann) ein, ob die Liste alles klärt. Wenn nicht, kommt als letzte Rückfrage eine eigene des Begleiters mit einem Antwortfeld und dem Hinweis, dass er sie selbst stellt. Die Antwort in Worten liest ein dritter Anlass („Freie Antwort beim Kalender einrichten“) als Änderungen an den Antworten — nur Felder, die der Bogen schon hat, jedes in seinen Grenzen geprüft. Der Vorschlag nennt dann in einem Satz, was sich geändert hat; wirksam wird es erst mit „Übernehmen“. Ohne Antwort, ohne Modell oder wenn nichts zu lesen war, bleibt der Vorschlag, wie er war. Solange gelesen wird, sagt der Knopf „Liest deine Antwort …“.
Der kurze Weg für Schlaf, Puffer und Weg (seit 15.10.2026, S-261015-fahrtzeit-schlaf). Christian am 14.10.2026: Fahrtzeit, Schlaf und der Puffer zwischen Aufstehen und erster Fahrt sollen „durch wenige Klicks ohne tausend config-Einstellungen“ einzurichten sein. „Ändern“ an den Zeilen Tagesrhythmus und Wege führt darum nicht mehr in den ganzen Fragebogen, sondern in drei Entscheidungen:
- Wie sieht eine Uni-Woche aus? (bei „Wege“ beginnt er mit 2, Zurück führt hierher);
- Wie kommst du hin? — bei Bus oder Bahn steht die Frage nach dem Fahrplan gleich darunter statt als eigene Rückfrage;
- der Vorschlag mit Übernehmen. Wäre man erst nach der Losfahrzeit fertig, hat er das schon gelöst — früher aufstehen, wenn das vor Mitternacht geht, sonst schneller fertig werden — und zeigt die drei Möglichkeiten zum Umstellen über dem Probetag. „Zurück“ gibt die eigene Angabe wieder.
Die übrigen Tage fragt der kurze Weg nicht; sie bleiben, wie sie sind. Auf /calendar selbst steht von der Einrichtung nur der Knopf Einrichten im Kopf.
Der Vorschlag („So würde ich es einrichten“) zeigt je Einstellung einen Satz mit Haken; Verbinden, Abonnieren und Teilen stehen als Satz mit Dorthin, weil sie eine Anmeldung oder eine Adresse brauchen. Darunter ein Probetag als Leiste über 24 Stunden: Schlaf, Fertigmachen, Weg, Puffer und die erste Veranstaltung, mit einer Legende in Uhrzeiten; ist man erst nach der Losfahrzeit fertig, steht „Knapp: …“ darunter. Gesetzt wird erst mit Übernehmen; danach steht über dem Stand Übernommen. mit Rückgängig, das den vorigen Stand zurückschreibt. Seit dem 16.10.2026 (K3 A) geht Übernehmen über LIFE_CALENDAR_EINRICHTUNG_UEBERNEHMEN: Der Server ruft über das Schreibprotokoll des Begleiters dieselben Werkzeuge, die auch er ruft (kalender_tagesrhythmus_setzen, kalender_wege_setzen), mit dem Weg bestaetigt und ihren Gegenzügen, nur für was sich ändert. Die Übernahme steht damit unter „Was der Begleiter geändert hat“. Geht ein Teil nicht durch, nimmt der Server den anderen zurück, und der Schirm meldet den Fehler. Rückgängig nimmt dann die Zeilen des Protokolls zurück (LIFE_CALENDAR_EINRICHTUNG_ZURUECKNEHMEN); geht das nicht, weil inzwischen etwas anderes daran geändert wurde, verweist die Meldung auf „Von Hand: alle Regeln und Einstellungen“. Ohne Begleiter oder ohne sein Protokoll schreibt der Kalender selbst, und Rückgängig schreibt den vorigen Stand wie bisher über LIFE_CALENDAR_TAGESRHYTHMUS_SETZEN und LIFE_CALENDAR_WEGE_SETZEN zurück.
Im Blatt (seit 16.10.2026, R2): Woche und Tag zeigen den übernommenen Tagesrhythmus als blasse Bänder hinter den Terminen — Schlaf in Stein, Fertigmachen im Ton der Auskunft, beide bei 14 % Deckung, ohne Klick und ohne Vorleser. Das Raster reicht dafür vom Aufstehen bis zum Schlafengehen, statt bei der Vorgabe 7 bis 21 Uhr abzuschneiden; ein Schlafengehen nach Mitternacht zählt zum nächsten Morgen. Ohne Rhythmus, oder wenn LIFE_CALENDAR_TAGESRHYTHMUS scheitert, bleibt das Raster, wie es war. In den Abgleich geht es nur mit dem Haken Tagesrhythmus und Wege an der Adresse für andere Kalender (unten, seit 16.10.2026).
Die gedämpften Unterschalter unter „Was geschrieben wird“ stehen bei ausgeschaltetem Abgleich auf 0,75 Deckkraft statt 0,55 (Guide §17; bei 0,55 maß /ansehen 2,3 : 1).
Gestaltung nach iCloud und Google (seit 14.10.2026, E-261013-kalender-wie-icloud)
Auf die Rückmeldung „ich glaube du merkst selber wie hässlich der kalender ist" hin sieht das Blatt aus wie die Kalender, die man kennt:
- Das Raster ist eine Fläche. Woche und Monat stehen nicht mehr als Kästchen mit Abstand nebeneinander; die Tage stoßen aneinander und teilen sich eine Linie, außen runde Ecken. Heute ist die Spalte auf Karton statt schwarz umrandet, im Monat liegen die Tage des Nachbarmonats auf Karton statt halb durchsichtig.
- Der Tageskopf zeigt den Wochentag klein und halbfett („Mi“) und darunter die Zahl groß; heute steht die Zahl auf einer runden Scheibe in der Schrifttinte, ebenso im Monat — unbunt, weil die Heute-Markierung keine Handlung ist (Guide §3.1). Vorleseprogramme hören weiter „Mi., 14.10.".
- Ein Termin trägt seine Kategorie in der Fläche: Papier, zu einem Fünftel mit ihrer Farbe getönt (gewählt gut ein Drittel), davor der Streifen wie bisher, runde Ecken. Im Raster steht der Titel fett zuerst und die Uhrzeit darunter; Wörter brechen an der Silbe.
- Der Kopf folgt Google: „Heute", die beiden Pfeile als runde Knöpfe ohne Rand, dann groß der Zeitraum, die Ansichten am Ende.
- Am Telefon zeigt ein Termin im Monatsfeld nur seinen Titel, ohne Zeichen und Uhrzeit; vorher blieben davon nur Auslassungspunkte. Seit dem 15.10.2026 stehen dort Punkte (nächster Abschnitt).
Am Telefon: drei Tage, Punkte im Monat (seit 15.10.2026, E-261014-kalender-telefon-wenige)
Die Sichtprüfung nach der Neugestaltung fand am Telefon sieben Spalten zu je gut vierzig Pixeln, in denen „Sprechstunde“ in drei Stücke brach.
- „Woche“ heißt am Telefon „3 Tage“ und zeigt drei Tage ab dem Anker, nicht ab dem Wochenanfang: Wer am Donnerstag nachsieht, sieht Donnerstag bis Samstag. Die Pfeile heißen „Vorige Tage“ und „Nächste Tage“ und blättern um drei. Ab 600 Pixeln bleibt es die Woche.
- Im Monat ist am Telefon jedes Feld ein Knopf (72 Pixel hoch, Guide §16.1 verlangt 44). Statt abgeschnittener Titel stehen bis zu drei Punkte in der Farbe der Kategorie, darüber hinaus „+n“; ein Tipp öffnet den Tag. Vorleseprogramme hören „Donnerstag, 24. September, ein Termin“.
- „Zu welchem Tag“ ist Denotatos eigenes Datumsfeld (
DateField) statt<input type="date">, das auf einem englischen Gerät „10/14/2026“ schrieb und einen weißen Systemkalender aufklappte. - Datumsfeld und Suche stehen am Telefon hinter der Lupe im Kopf des Blatts (seit 16.10.2026, KN-261014-woche-bild, Schritt 2). Offen nahmen sie dem Raster eine halbe Bildschirmhöhe. Ein Tipp auf die Lupe („Tag wählen oder suchen“) öffnet die Zeile; eine laufende Suche hält sie offen, damit nichts unsichtbar filtert.
- Die Legende steht am Telefon in einer Zeile und wird seitlich gewischt, statt in zwei, drei Reihen umzubrechen (seit 16.10.2026).
- Die Spalte von heute trägt 7 % Schrifttinte über dem Papier statt Karton; Karton lag im Dunklen nur sechs Stufen über dem Papier.
- Der doppelte Satz „Denotato schreibt in keinen fremden Kalender“ war schon mit KN-261014-woche-bild auf einen geschrumpft: Er steht nur noch im Vorlagenangebot der Einrichtung.
Aussehen aus dem Stilpaket (seit 19.10.2026, E-261018-zeitraster-i-rezept)
Die drei Zeitraster — das Stundenraster für Tag und Woche, das Monatsblatt samt Agenda und das Wochenraster des Stundenplans — nehmen ihr Aussehen aus dem Rezept zeitraster des aktiven Stilpakets (theme/paket/stilpaket.ts, für Legacy theme/pakete/legacy/zeitraster.ts), nicht aus festen Werten im Raster. Jeder Eintrag trägt seine Ebene als Attribut — Termin, Stundenplan, Lernzeit oder freier Tag (data-layer), dazu Ausfall oder Verlegung (data-change) — und seine Kategorie (data-category). So kann ein Paket Kategorien auch ohne Farbe unterscheiden, etwa mit einem Kürzel vor dem Titel, das aus dem Namen der Kategorie abgeleitet wird; „Vorlesung“ und „Vortrag“ ergeben dabei beide „Vo“.
Die Jetzt-Linie im Stundenraster nennt Uhrzeit und Titel des laufenden Termins. Die Beschriftung steht in seiner Kategoriefarbe, so weit zur Schrifttinte gezogen, dass sie auf jeder Fläche der zwölf Szenen mindestens 4,5:1 erreicht (terminflaeche.test.ts). Unter dem Legacy-Paket sind Beschriftung und Kürzel nur für Vorleseprogramme da, und das Bild bleibt wie vorher; sichtbar werden sie in den neuen Paketen. Ins Wochenraster des Stundenplans kommt die Jetzt-Linie vorerst nicht.
Ein Raster für Kalender und Stundenplan (seit 20.10.2026, E-261016-bausteine-iii)
Stundenraster, Monatsblatt und Agenda sind ein Baustein Zeitraster (frontend/src/components/bausteine/zeitraster/: HourView, MonthView, AgendaView). Der Kalender zeichnet ihn über die Hülle client/Kalenderblatt.tsx, der Seitenbaustein „Wochenraster“ des Stundenplans über stundenplan/client/Wochenbaustein.tsx; gerechnet wird in @shared/handlers/zeitraster. Beide setzen an jedem Eintrag dieselben Attribute: die Ebene (data-layer: Termin, Stundenplan, Lernzeit, freier Tag), die Änderung (data-change: Ausfall, Verlegung, Zusatz) und die Kategorie (data-category, Regel rasterkategorie). Seit E-261019-zeitraster-kategorie kennen Stundenraster und Monatsblatt auch die Verlegung, und ein Kalendertermin im Wochenraster trägt seine Kategorie. Unter Legacy sieht das Raster aus wie vor dem Umbau; auf dem iPad quer reicht es bis an den rechten Rand, eine Grenze von 960 Pixeln gibt es nicht.
Termin am Termin, Kategorien links (seit 09.10.2026, W-261009-kalender-wie-google)
Ein Klick auf einen Termin im Blatt öffnet seine Einzelheiten als Aufklapper am Termin — rechts daneben, wenn dort Platz ist, sonst links, sonst darunter, immer ganz im Bild. Der Aufklapper ist ein nicht-modaler Dialog (Rolle dialog, benannt durch den Titel des Termins, davor das Zeichen der Art in der Farbe der Kategorie, ohne Zeichen ein Punkt in dieser Farbe). Der Fokus geht beim Öffnen hinein und beim Schließen zurück auf den Termin; schließen lassen ihn Esc, das Kreuz, ein Klick daneben und ein zweiter Klick auf denselben Termin. Ein Klick auf einen anderen Termin schließt ihn und öffnet dessen Einzelheiten. Bis 600 Pixel Breite ist er das Blatt an der Unterkante, wie jedes Fenster am Telefon. Unter dem Blatt steht kein Einzelheitenfach mehr. Gebaut ist er als components/ui/Aufklapper.tsx aus dem nicht-modalen Radix-Dialog (wie das Datumsfeld) und Modal.
Ab 1200 Pixeln steht die Legende als Spalte links vom Blatt: je Kategorie eine Zeile mit einem Farbkasten, der zugleich Haken ist, und dem Namen; ein Klick auf Kasten oder Namen blendet die Kategorie aus oder ein. An eigenen Kategorien steht am Ende der Zeile ein Stift (Zeichen bearbeiten, Name „„Sport“ bearbeiten“), der wie „Bearbeiten“ im Menü in die Einrichtung führt. Was ausgeblendet ist, merkt sich das Gerät wie bisher (denotato.kalender.verborgen). Schmaler bleibt die Legende als Reihe über dem Blatt, mit dem Menü aus dem vorigen Abschnitt — zwischen 900 und 1199 Pixeln, also auf dem iPad quer und dem iPad Pro hochkant, damit das Raster die Breite füllt. Bis zum 18.10.2026 lag die Grenze bei 900 Pixeln; auf dem iPad quer blieben dem Raster damit rund 670 Pixel, seither rund 900 (E-261018-zeitraster-i-rezept).
Die Tabelle nennt die Abschnitte beider Schirme; von Verbindungen bis Nach draußen stehen sie auf der Einrichtung.
| Abschnitt | Inhalt |
|---|---|
| Meine Woche | ganz oben: die Wochenansicht mit Stundenraster — sieben Spalten, eine Stundenleiste links, Überlappendes nebeneinander, Ganztägiges in einer eigenen Zeile darüber, eine Jetzt-Linie am heutigen Tag (seit 22.09.2026, Punkt 30); zwei Blöcke, die sich überschneiden, tragen seit dem 23.09.2026 (N134) zusätzlich das Wort „doppelt" mit dem Zeichen warnung davor; steht der Abgleich aus, warnt oben ein Kasten mit demselben Zeichen. Seit dem 23.09.2026 steht der Stundenplan mit darin (G1): Vorlesungen, Übungen, Praktika und Sportblöcke, jedes Vorkommen einzeln, mit Uhrzeit im Raster und damit mit Kollisionsrand gegen Termine und gegeneinander. Ausgefallene Stunden und die Lehrveranstaltungen der vorlesungsfreien Tage stehen nicht da — Sport, Arbeit, Lernen und Sonstiges an einem vorlesungsfreien Tag schon (seit 23.09.2026, Bens Entscheidung E2); an einem Feiertag fehlt alles, was nicht ausdrücklich für ihn eingetragen ist (seit 23.09.2026, C37) —, eine verlegte nur einmal, an ihrer neuen Stunde |
| Legende und Filter | ab 1200 Pixeln eine Spalte links vom Blatt mit Farbkasten als Haken und Namen je Kategorie (seit 09.10.2026, W-261009-kalender-wie-google; bis zum 18.10.2026 ab 900 Pixeln), schmaler — auch auf dem iPad quer — eine Reihe Farbtupfen mit Namen — zugleich die Schalter, mit denen man eine Kategorie ausblendet. Solange es life.calendar_categories nicht gibt, sind es Denotatos vier feste Arten, und ein Satz darunter sagt das (seit 22.09.2026); jeder der vier Tupfen trägt seit dem 23.09.2026 (N134) zusätzlich das Zeichen seiner Art — echte, selbst angelegte Kategorien bekommen keins, sie haben keine feste Art. Seit dem 23.09.2026 trifft der Klick (G1): Die Vorschauzeile trägt die kategorieId, die der Sammler gerechnet hat, und Legende und Filter fragen dieselbe Kennung — vorher schrieb die Legende eine Kennung und der Filter fragte eine Art, und die Schnittmenge war leer. Ohne eigene Kategorien sind es Denotatos feste Arten plus Stundenplan |
| Einzelheiten eines Termins | wer einen Block anklickt, bekommt seit dem 09.10.2026 einen Aufklapper am Termin (am Telefon das Blatt an der Unterkante), vorher ein Fach unter dem Blatt: Wann, Quelle im Klartext (Person, Ereignis, Prüfung, To-Do, Tagesmaß, Abonnement), Kategorie und, wo es einen gibt, den Weg zum Bearbeiten (seit 22.09.2026); der Titel trägt seit dem 23.09.2026 (N134) das Zeichen der Art. Bei einer Tageszusammenfassung steht darin seit dem 23.09.2026 (H2) die Liste ihrer Posten — eine Zeile je fälliger Sache, mit der Uhrzeit, wenn die Frist eine hat, dem Wort „To-Do" bzw. „Wiedervorlage" dahinter, und dem Namen als Verweis auf die Aufgabe. Der Tag selbst führt weiterhin nirgendwohin, und das Fach sagt jetzt, warum: „Der Tag selbst ist gerechnet und hat keine Zeile, die man öffnen könnte — die Posten oben haben sie." Seit dem 11.10.2026 (F-261011-termin-aufklapper) trägt der Aufklapper eines eigenen, einzelnen Termins mit Uhrzeit (derselbe Fall, den das Raster ziehen darf, verlegbar) den Knopf Bearbeiten: Titel, Tag, Beginn und Ende, dazu Speichern und Abbrechen (Terminbearbeiten.tsx, gespeichert über LIFE_EVENT_SAVE; Ort, Personen und Wiederholung bleiben stehen). Nach dem Speichern schließt der Aufklapper, und das Blatt lädt neu. Die Kategorie hängt „Nur an diesem Tag“ um, für einen einzelnen Termin dasselbe. Serien, Geburtstage, Prüfungen und gespiegelte Termine behalten nur den Weg zur Quelle Seit dem 15.10.2026 (S-261015-kalender-faellig-symbol) steht unter den Posten einer Tageszusammenfassung der Haken Symbol statt „Fällig:“ vor dem Titel (Einstellung kalender.faellig.symbol, Vorgabe an). An: Im Blatt trägt die Zusammenfassung keinen Vorsatz mehr, nur das Zeichen der Art davor; in fremden Kalendern steht ⏰ statt „Fällig: “, und bei mehr als zwei Posten entfällt die Zahl vorn („⏰ A…, B… +2“). Aus: wieder „Fällig: …“ bzw. „4 fällig: …“. Der Schalter wirkt im Blatt sofort, draußen mit dem nächsten Abgleich |
| Verbindungen | eine Zeile je Anbieter — Google und iCloud getrennt, jede mit dem gemeinsamen Zustandssatz, dem Konto beim Dienst und dem letzten Fehlschlag des Dienstes (seit 22.09.2026, B2). Unter einer verbundenen Zeile steht seit dem 23.09.2026 ihr eigener letzter Abgleich und die Zahl der Termine, die Denotato bei diesem Anbieter geschrieben hat — vorher Googles Zeitpunkt und die Summe über alle (F60). Ein Anbieter, der nicht gewählt ist, während ein anderer läuft, zeigt keinen Fehlschlag. Vorher stand hier ein einziger Zustand, der aus einer Abfrage mit anbieter = 'google' kam — wer nur iCloud verbunden hatte, las „Kein Google-Konto verbunden"; ein Fehlschlag trägt seit dem 23.09.2026 (N134) das Zeichen warnung vor dem Satz. Seit dem 24.09.2026 (B17, Durchsicht) gilt Google auch dann als verbunden, wenn sein Merkmal noch in der alten Spalte auf den Umzug wartet — ohne CREDENTIAL_KEY oder zwischen Start und erstem Umzug; vorher hieß das hier „nicht verbunden“, obwohl der Abgleich die Lage als „ohne Zugangsdaten“ kannte. Die iCloud-Zeile nennt kein Konto, und das ist gewollt (N350, C47): Die Apple-ID liegt nur verschlüsselt im Zugang und wird weder mitgeschrieben noch zum Anzeigen entschlüsselt |
| Abgleichbericht | nach „Jetzt abgleichen" oder „Erst durchrechnen": seit dem 23.09.2026 (N5) steht der Satz über den doppelten Weg (Strom und CalDAV im selben Apple-Konto) nur noch, wenn der Strom eine Adresse hat, eine Art ausliefert und eine freigegebene Kategorie Termine dieser Art über CalDAV schreibt — und er nennt diese Kategorien; vorher genügte eine Adresse, auch mit drei ausgeschalteten Schaltern. angelegt · geändert · umgehängt · gelöscht · unverändert, die Zahl der zurückgesetzten und die der nicht angefassten Termine, dazu die Zahlen je Quelle, Hinweise und Fehler (seit 22.09.2026, B-35); seit dem 23.09.2026 (N134) trägt die Zeile der nicht angefassten Termine das Zeichen schild, jede Fehlerzeile das Zeichen warnung. Seit dem 23.09.2026 zählt diese Zeile zwei Fälle, und der Satz daneben nennt beide: fremde Termine, die Denotato nicht anfasst, und eigene, die Denotato löschen wollte, an denen draußen aber jemand gearbeitet hat — die bleiben stehen (Entscheidung von type-Ignore, docs/auftrag-kalender/ENTSCHEIDUNGEN.md Nr. 6). Der Grund steht dort: eine Rücksetzung lässt sich wieder herstellen, eine Löschung nicht. Seit dem 23.09.2026 (N148, E1) steht darunter eine Tabelle je Zielkalender — Zielkalender · Kategorien · Einträge · Plan · Draußen —, z. B. „GOLD · Uni · Vorlesungen + Übungen + Praktikum · 12 (davon 9 Stundenplan, nicht geschrieben) · 0 neu · 0 geändert · 0 umgezogen · 0 gelöscht · noch nicht“; sie nennt auch Kategorien, die (noch) nicht schreiben, mit dem Kalender, in den sie schrieben. Darüber eine Zeile mit der Zahl der angekündigten Termine (eine Kategorie soll schreiben, ist aber nicht freigegeben) und je Kategorie ein Hinweis. Nachgebessert am 23.09.2026: Die Spalte „Plan“ nennt die Umzüge mit (vorher fehlten sie, obwohl ein Zielwechsel genau sie auslöst), und solange eine Kategorie im Kalender noch wartet (angekündigt, oder „Nach draußen schreiben“ aus), steht darunter „nach Freigabe: …“ — was der erste Lauf nach der Freigabe dort anlegte, änderte, umzöge und löschte (planNachFreigabe). „Draußen“ heißt seitdem „steht beim Anbieter schon“ — ein von Hand gelöschter Kalender und bei Google ein neuer Zielname gelten als „noch nicht“; vorher genügte Denotatos eigene Zeile. Kopf aus Stein, Zahlen in Mono nach dem Guide. Hält ein eingefrorener Kalender etwas zurück, sagt es ein Hinweis: „Kalender „GOLD · Termine" ist eingefroren, solange „Termine" nicht freigegeben ist — 1 Termin(e) nicht geloescht, 0 nicht umgezogen.“ Seit dem 24.09.2026 gewinnt Denotato auch draußen (BE67, N229, N241): Jeder Lauf fragt je GOLD · …-Kalender einmal nach den Marken aller eigenen Termine (bei iCloud ein calendar-multiget, bei Google events.list mit gelöschten), setzt einen draußen verstellten zurück (mitgezählt unter „zurückgesetzt“ und „geändert“) und legt einen draußen gelöschten neu an; dafür steht eine eigene Zeile da: „{n} draußen gelöscht und von Denotato wieder angelegt — ändern oder löschen in Denotato“. Fremde Kalender, Termine ohne Denotatos Marke und eingefrorene Kalender fasst das nicht an; kann ein Kalender nicht gelesen werden, steht ein Hinweis da, und es wird nichts geschrieben. Der Probelauf zählt beides, ohne zu schreiben. Das Morgenbriefing nennt es (docs/seiten/dashboard.md). |
| Während ein Abgleich läuft | der gedrückte Knopf trägt statt seines Namens „Gleicht ab …" bzw. „Rechnet durch …" (aria-busy), alle drei Knöpfe — die zwei des Abgleichs und „Einstellungen speichern" — sind gesperrt, und darunter steht der Satz „Der Abgleich läuft. Er fragt jeden verbundenen Anbieter nacheinander; antwortet einer nicht, bricht Denotato nach einer festen Frist ab und meldet es hier." als role="status" (seit 23.09.2026, A30). Vorher wurden die Knöpfe nur grau, und ein wartender Abgleich sah aus wie ein hängender Schirm |
| Was geschrieben wird | vier Schalter: Geburtstage · Prüfungen · Ereignisse · Fälliges (To-Dos und Wiedervorlagen), dazu Moodle-Fristen, sobald der Server Migration 328 kennt (BE47, Vorgabe aus, life.calendar_settings.write_moodle; ohne die Spalte fehlt der Haken, und ein gesendeter Wert bleibt wirkungslos); der Schalter wirkt auf Abgleich und Vorschau, nicht auf die .ics-Adresse; steht der Hauptschalter aus, warnt darunter ein Kasten mit dem Zeichen warnung (seit 23.09.2026, N134) — bis zum 14.10.2026 stand derselbe Kasten auch oben unter „Meine Woche" |
| Vorlauf in Tagen | wie weit im Voraus geschrieben wird |
| Erinnerung (Minuten vorher) | wie lange vorher ein Wecker klingeln soll — seit dem 22.09.2026 gilt die Zahl für den Strom nach draußen, wo jeder Termin einen Alarmteil bekommt; im Google-Kalender gilt weiterhin Googles eigene Vorgabe (Punkt 35) |
| Fälliges-Modus | „Ein Termin je Frist" · „Eine Zusammenfassung pro Tag" · „Fälliges bleibt draußen" |
| Fremde Kalender | die Kalender des verbundenen iCloud-Kontos — seit dem 23.09.2026 findet der Abgleich sie selbst (BE43, Bens Befund K3): jeden, der Termine aufnimmt, außer Denotatos eigenen GOLD · …-Kalendern und den Erinnerungslisten. Jede Zeile: Name mit dem Farbtupfen davor (die Kategorie, sonst die Farbe von drüben; bis zum 10.10.2026 ein Farbstreifen links, ES-261009-farbige-seitenstreifen, E11), ein Satz zum Stand — „Neu gefunden — nicht eingelesen." für einen, den noch niemand entschieden hat, „Eingelesen am … · N Termine." für einen eingeschalteten (der Tag in Sprache und Zone des Kontos, seit dem 09.10.2026) —, der Schalter In Denotato spiegeln und die Kategorie. Ein neu gefundener läuft nie still mit. Gespiegelte Termine stehen im Blatt, in heute, im Briefing und im Stundenplan daneben; was schon als Denotato-Termin oder Vorlesung zur selben Minute mit passendem Titel dasteht, erscheint nicht noch einmal — und aus einem Kalender, der ein Export des Stundenplans ist, auch ohne passenden Titel, wenn der Titel dort als Serie wiederkehrt und nicht widerspricht (seit 23.09.2026, AP4; Regel unter „Woher die Daten kommen"). Seit dem 24.09.2026 (N216, BE41) steht hier auch jedes .ics-Abo als eigene Zeile — eingeschaltet vom Anlegen an, die Serien aufgeklappt wie bei iCloud; wer es ausschaltet, dem schaltet es kein Abruf wieder ein. Die Kategorie eines Abos wird nur hier gewählt. Nach draußen geht davon nichts. Seit dem 24.09.2026 (N229, BE60) spiegelt eine Kategorie oder schreibt, nie beides: In der Auswahl stehen Kategorien, die nach draußen schreiben, mit „(schreibt hinaus)“ und sind für einen gespiegelten Kalender gesperrt. Hängt ein abbestellter an einer solchen, ist „In Denotato spiegeln“ gesperrt, und darunter steht „„{name}“ schreibt nach draußen — zum Spiegeln erst eine andere Kategorie wählen.“ Hängt ein abonnierter dort noch aus der Zeit davor, steht rot „„{name}“ schreibt nach draußen und spiegelt zugleich diesen Kalender. Wähle eine andere Kategorie oder bestell ihn ab.“ — umgehängt wird nichts von selbst. Der Server lehnt alle drei Wege mit derselben Meldung ab (Kategorie auf Schreiben schalten, Kalender zuordnen oder abonnieren, Abo in eine schreibende Kategorie anlegen); Abbestellen, Lösen und Umfärben gehen immer |
| Abonnierte Kalender | die eingetragenen .ics-Adressen mit Name, dem gemeinsamen Zustandssatz (verbunden seit …, seit 21.09.2026, A24), Zahl der Termine und dem Grund, wenn der letzte Abruf nicht ging (seit 19.09.2026, BE11); seit dem 23.09.2026 (N134) trägt ein Fehlschlag das Zeichen warnung. Ein pausiertes Abonnement trug kurz das Zeichen gesperrt, das war falsch (Sperre statt Ruhe, Prüfer-Befund) — danach stand „Pausiert" ohne Zeichen und das Wort selbst in Blau (status.info, BE11). Seit dem 30.09.2026 (E12) trägt „Pausiert" das eigene Zeichen pause in Blau, und das Wort ist neutral wie überall nach N134. Seit dem 24.09.2026 (BE40) steht unter dem Adressformular ein zweites für eine .ics-Datei, die man schon hat — etwa den Export aus einem anderen Kalenderprogramm. Ein Abo aus einer Datei zeigt statt seiner Kennung gold-datei:… den Satz „Aus einer Datei — sie erneuert sich nicht. Für neuere Termine die neuere Datei hochladen und diese hier kündigen."; der Pausiert-Satz fehlt dort, weil es immer ruht. Seit dem 24.09.2026 (BE41, N216) trägt jede Zeile die Farbe ihrer Kategorie — seit dem 10.10.2026 (ES-261009-farbige-seitenstreifen, E11) als Tupfen vor dem Namen, wie in der Legende, statt als Streifen links — und nennt sie: „Kategorie „{name}“ — ändern unten unter „Fremde Kalender“.", ohne Kategorie „Ohne Kategorie — zuordnen unten unter „Fremde Kalender“." Eine Auswahl steht an der Abozeile nicht — ein Weg, nicht zwei. Die Zahl der Termine zählt, sobald der Spiegel einmal gelesen hat, was die Ansichten zeigen: die Vorkommen im Fenster, ohne abgesagte Seit dem 08.10.2026 (VA-261008-blackboard-kalender) steht über dem Adressformular ein Satz, wenn die Einrichtung des Kontos eine Lernplattform der Art Blackboard hat: „Aus Blackboard: Kalender öffnen, oben das Zahnrad, dann im Menü „Share Calendar“ den Link kopieren und hier einfügen. Fristen daraus schlägt Denotato als To-dos vor.“ Der Satz hängt an der Art, nicht an der Einrichtung. Seit dem 09.10.2026 (VA-261009-hinweis-kalender-abo) bekommt ILIAS seinen eigenen: „Aus ILIAS: Kalender öffnen (auf dem Dashboard oder unter „Persönlicher Schreibtisch“), dort „Abonnieren“ wählen, den Link kopieren und hier einfügen. …“; Moodle (liest Denotato mit Schlüssel) bekommt keinen. Seit dem 09.10.2026 (VA-261009-abo-hinweis-jede) bekommt jede andere Plattform den allgemeinen Satz mit ihrem Rechnernamen: „Aus deiner Lernplattform ({rechner}): im Kalender nach „Exportieren“, „Abonnieren“ oder „iCal“ suchen, den Link kopieren und hier einfügen. …“. Seit dem 11.10.2026 (VA-261010-lernplattformarten) sind Stud.IP und Canvas eigene Arten ohne Anbieter, und jede bekommt ihren Satz: „Aus Stud.IP: unter „Planer“ den Terminkalender öffnen, in der Seitenleiste „Kalender abonnieren“ wählen (je nach Fassung unter „Exportieren“), den Link kopieren und hier einfügen. …“ und „Aus Canvas: links „Kalender“ öffnen, rechts unten „Kalender-Feed“ wählen, den Link kopieren und hier einfügen. …“. Ein Abo, dessen Rechner genau der Lernplattform der Einrichtung gehört, meldet bei jedem Abruf (Eintragen, „Jetzt lesen“, Zeitgeber) seine Fristen an die Aufgabenverwaltung: Termine ohne Dauer und kurze Termine mit Fristwort im Titel (calendar/shared/abofristen.ts), ohne ganztägige, Serien und Abgesagtes. Sie werden To-do-Vorschläge mit der Herkunft „Aus einer Frist im Kalender deiner Lernplattform“; ein Abo aus einer Datei meldet keine |
| Nach draußen | die geheime Adresse, unter der Denotato selbst einen .ics-Strom ausliefert, drei Schalter dazu und die Zahl der Abrufe (seit 21.09.2026, BE12). Unter Einstellungen → Zugangsdaten steht derselbe Strom seit dem 24.09.2026 als Kachel unter „Nach innen“ — dort nur sein Zustand, nie die Adresse (N205) |
| Woche · Tag · Monat · Agenda | vier Segmente einer Kapsel (seit 28.09.2026, N400). Woche und Tag zeichnen das Stundenraster, der Monat die sechs Wochen mit 42 Feldern, die Agenda eine nach Tagen gruppierte Liste ab dem angezeigten Tag (Agenda seit 22.09.2026); bewusst ohne Zeichen (Stand 23.09.2026, N134) — der Styleguide (§7.3) verlangt ein Zeichen für alle vier Reiter oder für keinen, und für „Woche"/„Tag"/„Monat"/„Agenda" gibt es kein passendes Viertel in der Registry, das nicht mit einer Terminart kollidiert |
| Kalenderwoche | „KW 39" neben der Zeitspanne, in Woche und Tag — immer nach ISO 8601, auch bei „Sonntag zuerst": Wer „KW 40" sagt, meint die Zählung aus Fahrplänen und Vorlesungsverzeichnissen (seit 22.09.2026) |
| Sprung und Suche | ein Datumsfeld („Zu welchem Tag") und ein Suchfeld über Titel und Beschreibung; bei aktiver Suche steht daneben „3 von 42" (seit 22.09.2026). Am Telefon hinter der Lupe „Tag wählen oder suchen“ im Kopf (seit 16.10.2026) |
| weggefallen am 22.09.2026 — dieselbe Auskunft steht jetzt in der Agenda-Ansicht, und die gehört zum selben Filter und zum selben Suchfeld. Zwei Listen desselben Inhalts sind eine zu viel |
Jeder Termin der Vorschau führt dorthin, wo er herkommt. Eine Prüfung führt seit dem 03.10.2026 (NV15, N499) auf /study?a=exams&id=<Prüfung>: der Abschnitt Prüfungen öffnet sich, die Karte liegt auf der leisen Fläche des Überfahrens (bis zum 10.10.2026 ein Streifen am Rand, E11) und rollt ins Bild. Vorher landete der Weg nur auf /study, ohne die Prüfung zu zeigen.
Ihre Beschreibung nennt die Art seit dem 14.10.2026 als Wort („Klausur. Aus Denotato.“), hier wie in jedem fremden Kalender; vorher stand dort der Wert der Aufzählung, „klausur.“ (F-261013-pruefungsart-steht-roh).
Seit dem 23.09.2026 (H2) gilt das auch für Fälliges. Ein To-Do (game.tasks) führt auf /tasks?id=<Zeile>, und /tasks hebt die Zeile hervor — useMenuScreen liest ?id= als hervorgehoben und reicht es an die Datenansicht. Eine Wiedervorlage (study.exercise_attempts) führt auf /tutor ohne Kennung: quelleId ist dort die Kennung eines Versuchs, der Tutorschirm listet Aufgaben, und ein ?id=, das nichts trifft, behauptete etwas. Beide Wege stehen in quellziel (Kalendermenue.tsx) und gelten für den einzeln geschriebenen Termin genauso wie für jeden Posten einer Zusammenfassung — es ist dieselbe Funktion.
Fälliges zeigt nur Offenes (seit 24.09.2026, BE54). Ein To-Do, das auf done, fine oder scrapped steht (game.task_progress, die Liste CLOSED_STATUSES), fällt aus der Vorschau, aus kommende, aus dem .ics-Strom und aus dem Abgleich — dieselbe Bedingung wie im Briefing und in der Übersicht. Eine Wiedervorlage gilt nur aus dem letzten Versuch an einer Aufgabe, wie im Tutor; ein späterer Versuch löst die frühere ab. Fällt der letzte offene Posten eines Tages weg, fällt die Zusammenfassung ganz weg, und der Abgleich löscht sie in gold-faellig von selbst.
Abgegebene Blätter stehen mit Haken (seit 20.10.2026, W-261019-abgabe-vorlaeufig). Ein abgegebenes Übungsblatt steht in „Denotato · Prüfungen“ mit „✓“ vor dem Titel, solange die Abgabe vorläufig ist; der Termin behält seine Kennung und wird draußen geändert, nicht neu angelegt. Ist sie endgültig — „Ja“ an der Blattkachel, „Erledigt“ am Termin oder „korrigiert“ —, fällt der Termin aus dem Sammler und wird draußen gelöscht. Im Aufklapper eines vorläufigen Blattes steht „Abgegeben, noch vorläufig.“ mit dem Knopf „Erledigt“; danach bietet er „Rückgängig“. Das Blatt gehört dem Studium, der Kalender erreicht es über den Anschluss abgabe; fehlt das Studium, fehlt der Knopf. Klausuren und offene Blätter bleiben, wie sie waren.
Das Blatt — Monat, Woche, Tag (seit 17.09.2026)
Ein Raster aus sechs Wochen — immer sechs, nie fünf und nie sieben, damit das Blättern die Seite nicht springen lässt. Der Wochenanfang folgt der Einstellung zeit.wochenstart, die Wochentagsnamen kommen aus Intl und nicht aus einer zweiten Übersetzungsliste.
Warum ein Raster und nicht die Liste allein. Eine Liste nach Datum sagt, was ansteht; sie sagt nicht, wie dicht. Ob drei Prüfungen in derselben Woche liegen, sieht man erst, wenn die Woche eine Zeile ist. Die Liste bleibt darunter stehen: sie beantwortet „was kommt als nächstes?" und beantwortet es besser.
Die Farben sind eine Auskunft, keine Verzierung. Orange Geburtstag, blau Prüfung, grün Ereignis, gelb Fälliges — aus theme/terminarten.ts, gewählt aus derselben Farbreihe wie Skills und Interessengebiete. Eine unbekannte Art wird grau statt zu verschwinden.
Seit dem 23.09.2026 (N134) trägt der Titel zusätzlich ein Zeichen der Art — die Farbe stand bis dahin nur am linken Rand, und eine Farbe allein ist keine barrierefreie Auskunft. Geburtstag zeigt geburtstag, Prüfung pruefung, Ereignis kalender. Fälliges zeigt im Regelfall das neutrale aufgabe — „hier steht eine Frist" — und nur für den einen Termin, dessen Tag wirklich heute oder vorbei ist, faellig bzw. ueberfaellig (Styleguide §7.6: keine Uhr neben jedem Datum). Das Wort bleibt neutral, und das Zeichen trägt die Farbe der Art — mit einer Ausnahme in Monat und Agenda (Monatsblatt.tsx): ueberfaellig trägt dort die feste Warnfarbe (theme.colors.status.danger) statt der Kategoriefarbe, denn Rot ist hier die Auskunft „das war fällig und ist es nicht mehr geworden", nicht die der Kategorie (zeichenfarbe(), calendar/shared/terminZeichen.ts, Nachbesserung vom 23.09.2026). Welches Zeichen erscheint, folgt in der Legende darüber (nur solange sie die vier festen Arten zeigt) und in den Einzelheiten eines angeklickten Termins derselben Abbildung — die Warnfarben-Ausnahme fehlt dort noch (Punkt 72 unten).
Ein Termin ohne Ziel — das Tagesmaß, dessen Quelle der Tag selbst ist — wird kein Verweis. Ein toter Link sieht aus wie ein lebender, bis jemand klickt.
Ein Feld zeigt drei Termine und zählt den Rest („+2", der Rest im Zeigerhinweis) — aber nur im Monat. Ohne Grenze wächst die Zeile mit dem vollsten Tag darin, und Rasterzeilen sind gleich hoch — acht Termine an einem Dienstag machen alle sieben Felder dieser Woche hoch. Aus dem Monat würde eine Liste mit Rahmen, also genau das, was er ersetzen sollte.
Die Zeile „ganztags“ (E34, 15.10.2026) hat oben und unten Abstand aus dem Theme, damit ihre Beschriftung nicht an „07:00“ klebt; bei grobem Zeiger (Tablet, Telefon) ist ein Ganztagstermin 44 Punkte hoch, der Titel steht mittig und kürzt mit Auslassung.
Der ganze Tag passt hinein (24.10.2026, F-261024-kalender-ganzer-tag): Die Stundenhöhe der Woche und des Tages richtet sich nach der Fensterhöhe, sodass der Bereich von der ersten bis zur letzten Stunde des Tagesrhythmus ohne Scrollen zu sehen ist. Sie liegt zwischen 32 und 72 Pixel je Stunde; wird das Fenster so niedrig, dass 32 Pixel nicht reichen, scrollt das Blatt, und die Kopfzeile bleibt stehen. Die Kopfzeile mit den Wochentagen erbt die Fläche des Rasters und schließt bündig mit ihm ab, statt an den Ecken darüber hinauszustehen.
Drei Ansichten (seit 21.09.2026, S-calendar)
Der Monat beantwortet „wie dicht ist der September?", die Woche „was habe ich diese Woche vor?", der Tag „was ist heute noch?". Das sind drei verschiedene Fragen, und ein Monatsraster beantwortet nur die erste. Umgeschaltet wird oben rechts über Segmente in einer Kapsel (Segmentwahl, seit 28.09.2026, abgeleitet aus N400): eine benannte Gruppe „Ansicht“ mit aria-pressed. Bis dahin eine Reiterreihe mit role="tablist" — ohne Reiterfelder und ohne Pfeiltasten, also ein Versprechen an Vorleser, das sie nicht hielt.
Woche und Tag zählen nicht, sie zeigen. In sieben Feldern nebeneinander und erst recht in einem ist Platz; dort steht jeder Termin da. Damit ist auch der Weg zu den gezählten Terminen gebaut, den Punkt 1 verlangte: Wer wissen will, was hinter dem „+2" steckt, wechselt die Ansicht — vorher half nur der Zeigerhinweis, und der setzt eine Maus voraus.
In der Woche steht der Wochentag am Feld („Do., 17.09." statt „17"). Die Kopfzeile beschriftet die Spalten zwar, aber sie ist in der Wochenansicht die einzige Stelle, an der „Mi." steht, und auf einem Telefon scrollt sie weg.
Ein Anker, nicht drei Zustände. Das Blatt merkt sich einen Tag — im Monat seinen Monat, in der Woche seine Woche, am Tag ihn selbst. Drei Zustände wären drei Wahrheiten darüber, wo man gerade ist. Wer im Monat auf den Oktober blättert und dann auf „Tag" geht, ist im Oktober und nicht wieder heute. Ein Schritt mit den Winkeln zurueck und weiter ist entsprechend das, was die Ansicht zeigt: ein Monat, sieben Tage, ein Tag — und die Beschriftung sagt es („Nächste Woche", „Voriger Tag").
Gerechnet wird außerhalb: der Monat in @shared/handlers/zeit/monatsraster (dreizehn Zusicherungen), Woche und Tag im Bereich (calendar/shared/tage.ts, sechzehn). Zwölf weitere prüfen das Blatt selbst.
Der Endpunkt schnitt anfangs bei zwölf Zeilen ab — richtig für eine Liste, falsch für ein Raster: 42 Felder aus zwölf Einträgen zeigen einen leeren Monat und sagen nicht, dass sie ihn gekürzt haben. Seit dem 17.09.2026 kommen alle sechzig Tage heraus (Decke: 400 Zeilen), die Liste zeigt weiterhin zwölf und nennt den Rest.
Die Uhrzeit am Termin (seit 22.09.2026, S-calendar)
Wo es eine gibt, steht die Uhrzeit vor dem Titel — im Blatt wie in der Liste, in Ziffern gleicher Breite (tabular-nums, Style-Guide §9), damit die Spalte untereinander steht und nicht zappelt. Im Monat nur der Beginn, in Woche und Tag die Spanne („14:00–15:30"): Im Monatsfeld ist für eine Spanne kein Platz, und im Monat ist der Beginn ohnehin die Frage. Ein Termin, der über Mitternacht geht, zeigt nur seinen Beginn — ein Ende, das an einem anderen Tag liegt, wäre neben diesem Tag eine falsche Auskunft.
Der Server schickt keine Uhrzeit, er schickt einen Zeitpunkt. beginn und ende gehen als Zeitstempel in UTC hinaus und werden erst im Schirm mit zeit.uhrzeit() gelesen — Grundsatz 54: der Server rechnet in UTC und zeigt nie. Wer seine Zone umstellt, sieht dieselbe Zeile anders, ohne dass der Server etwas davon erfährt.
Was keine Uhrzeit hat, bekommt keine. Geburtstage, Prüfungen und Fristen sind in Denotato Tagesdaten; ein Ganztagstermin steht in life.events auf zwölf Uhr, weil Mitternacht eine Zone weiter der Vortag wäre. Beides als „12:00" hinzuschreiben wäre eine erfundene Auskunft — gelesen wird deshalb all_day, und wo es steht, bleibt die Zeile ohne Zeit.
Ganztägiges steht vor den Uhrzeiten desselben Tages, danach wird nach dem Beginn sortiert und erst zuletzt nach dem Titel. Der gemeinsame Sammler ordnet nur nach Tag und Titel; ohne diesen zweiten Griff stünde „Zahnarzt 09:00" unter „Abendessen 19:00", und ein Kalender, der die Stunden durcheinanderbringt, ist schlimmer als einer ohne Stunden. Die Ordnung liegt als reine Logik in calendar/shared/terminordnung.ts (elf Zusicherungen, Grundsatz 59), nicht im Schirm — sortiert wird an beiden Enden gleich.
Geholt werden die Zeiten neben der Vorschau, nicht in ihr. kalendervorschau ist der Anschluss kalender.vorschau, den der Stundenplan ruft; seine Form zu ändern hätte einen zweiten Bereich angefasst. Stattdessen liest calendar/server/ereigniszeiten.ts dieselbe Spanne ein zweites Mal — nur die Spalten starts_at und ends_at, nur aus life.events, nur ohne all_day — und legt das Ergebnis über die Vorschau. Ein Ende, das nicht nach dem Beginn liegt, wird verworfen statt geraten.
Blättern und Ziehen (seit 07.10.2026, BW-261007-kalender)
Der Zeitraum wechselt mit Richtung. Monat, Woche und Tag gleiten beim Blättern in Laufrichtung: vorwärts kommt das neue Blatt von rechts, rückwärts von links. Die Richtung folgt aus dem Vergleich des alten und des neuen Ankers, nicht aus dem Knopf — so nehmen auch „Heute“ und der Sprung zu einem Datum die passende Seite. Am Telefon blättert ein Wischen über das Blatt, ab einem Viertel der Breite oder mit einem kräftigen Schwung (blaetterziel in den Bewegungsbausteinen). Bei der Bewegungsstufe „aus“ wechselt das Blatt ohne Übergang.
In Woche und Tag lässt sich ein Termin ziehen und verlängern — mit Maus oder Stift. Wer den Block greift, zieht ihn in eine andere Stunde oder Spalte; wer den Griff am unteren Rand greift, ändert das Ende. Beim Loslassen rastet er mit einer Feder auf die Viertelstunde ein (calendar/shared/rasterzug.ts, gerechnet in Wanduhrzeit, damit ein Termin über die Zeitumstellung um 10:00 bleibt).
Verlegt wird erst nach Bestätigung (Christians Absprache vom 07.10.2026). Der eingerastete Termin bleibt als Vorschlag stehen, gestrichelt umrandet, und unten am Blatt haftet eine Leiste: „„Titel“ auf Mi., 07.10., 12:00–14:00 verlegen?“ mit Verlegen und Verwerfen. Erst „Verlegen“ schreibt (LIFE_EVENT_SAVE mit neuem Beginn und Ende); scheitert das, nennt die Leiste den Grund und der Vorschlag bleibt. Danach sagt sie „„Titel“ verlegt.“ und bietet Zurücknehmen — dasselbe tun Strg+Z und die Rücknahme der Kopfleiste. Ein Wechsel der Ansicht oder des Zeitraums verwirft einen offenen Vorschlag.
Ziehen lässt sich nur, was einem selbst gehört und eine Uhrzeit hat: ein einzelnes Ereignis aus life.events, nicht ganztägig, keine Serie (Feld verlegbar der Terminzeile, vom Server gesetzt). Alles andere — Stundenplan, Abo, Prüfung, Frist, Geburtstag — trägt keinen Griff.
Eine Veranstaltung eintragen und bearbeiten (seit 15.10.2026, KN-261014-woche-bild)
Kalender und Stundenplan werden ein Bild (Wahl B, F1 A). Unter dem Terminformular im Anlegefach steht „Veranstaltung eintragen …“; der Knopf öffnet das Formular des Stundenplans als Fenster („Veranstaltung eintragen“) mit allen Feldern, der Überschneidungswarnung gegen Plan und Kalender und „Weitere Gruppe“. Der Aufklapper einer Vorlesung, Übung oder eines Sportblocks trägt Bearbeiten statt „Dort bearbeiten“ und öffnet dasselbe Fenster mit der Veranstaltung, samt Wegtun. Nach dem Speichern schließt das Fenster, und das Blatt lädt neu. Das Fenster ist stundenplan/client/Veranstaltungsfenster.tsx, gereicht über den Anschluss stundenplan.Veranstaltungsfenster und erst beim ersten Öffnen geladen; ohne den Bereich Stundenplan heißt das Fach wieder „Termin“, und der Aufklapper behält den Verweis.
Ausfall und freie Tage im Blatt (seit 15.10.2026, KN-261014-woche-bild)
Ein abgesagtes Vorkommen steht blass und durchgestrichen an seiner Stunde, in der Farbe seiner Kategorie, und kollidiert mit nichts; der Hinweis sagt „… — fällt aus“. Ein freier Tag (Ferien, Feiertag, Brückentag aus study.freie_tage) steht als graues Ganztagsband, je Tag einmal, und gehört keinem Filter. Der Aufklapper einer Vorlesung trägt neben Bearbeiten den Knopf Fällt aus: er legt für diesen einen Tag eine Ausnahme „Ausfall“ an. Am abgesagten Vorkommen steht „Fällt an diesem Tag aus.“ und Findet statt, das die Ausnahme wieder aufhebt; Umhängen und Ausblenden fehlen dort. Beides läuft über den Anschluss stundenplan.faelltAus und stundenplan.findetStatt; danach lädt das Blatt neu.
Die Zeilen kommen nicht in kommende, sondern im eigenen Feld stundenplanlage der Statusantwort (ausfaelle, freieTage), gerechnet von stundenplanlage in calendarCollector.ts. So zählen Abgleich, Kollisionen, heute und das MCP-Werkzeug ein abgesagtes Vorkommen weiter nicht mit. Gezeigt werden nur Absagen über eine Ausnahme — ein Vorkommen, das wegen eines freien Tages entfällt, steht nicht noch einmal da, das Band sagt es schon.
Verlegen (seit 16.10.2026) öffnet im Aufklapper ein kleines Formular mit Beginn, Ende und dem Raum an diesem Tag; leer heißt „Raum wie immer“. Es legt über den Anschluss stundenplan.verlege eine Ausnahme „verlegt“ für genau diesen Tag an, ein zweites Verlegen überschreibt sie. Ein anderer Tag ist kein Feld: Er wäre ein Ausfall und ein Zusatztermin.
Ziehen (seit 16.10.2026): Ein stattfindendes Vorkommen einer Veranstaltung hat im Wochenraster einen Griff wie ein eigener Termin (ziehbar in Stundenraster.tsx); gezogen wartet es als Vorschlag, und „Verlegen“ legt dieselbe Ausnahme an, mit dem Raum der Veranstaltung oder dem, auf den eine frühere Verlegung ihn gelegt hat. In eine andere Tagesspalte gezogen, speichert es nichts, und die Leiste sagt: „Eine Veranstaltung rückt nur an ihrem Tag.“ „Zurücknehmen“ stellt den Stand vor dem Ziehen her (seit 16.10.2026, KN-261016-zuruecknehmen-ziehen): War das Vorkommen nicht verlegt, hebt es die neue Ausnahme auf; war es verlegt, setzt es die alte Verlegung samt Raum wieder. Dafür liest der Kalender vor dem Ziehen den Anschluss stundenplan.verlegungAm.
Sporthaken (seit 16.10.2026): Der Aufklapper eines Sporttermins — eine Veranstaltung der Art Sport oder ein Kalendertermin, den die Woche als Sport kennt — trägt an einem Tag, der war, das Kästchen Dabei gewesen. Es setzt denselben Haken wie die Zeile über dem Raster des Stundenplans (Anschluss stundenplan.hakenAm und setzeHakenAm). An einem Tag, der kommt, an einem abgesagten Vorkommen und ohne Sport steht es nicht da.
Lernzeiten (seit 16.10.2026): Rechnet der Stundenplan Lernzeiten vor, steht hinter den Kategorien ein Chip Lernzeiten (in der Spalte ein Haken), violett wie die Blöcke selbst. Das Blatt zeigt die vorgeschlagenen Blöcke dieser und der nächsten Woche, die noch nicht vorbei sind, als „Lernzeit: <Modul>“ (Anschluss stundenplan.lernbloecke). Der Chip blendet sie aus wie eine Kategorie und merkt sich das im Gerät; ein Bearbeiten hat er nicht; eingestellt wird unter „Einstellungen › Lernzeiten“, wohin seit dem 16.10.2026 auch der Aufklapper eines Blocks führt. Ohne Lernzeiten fehlt der Chip.
Nur der Stundenplan (seit 16.10.2026, F1 A): /stundenplan leitet auf /calendar?nur=stundenplan um. Dann stehen im Blatt nur Veranstaltungen und freie Tage, und die Legende zeigt alle übrigen Kategorien und die Lernzeiten als ausgeblendet. Der gemerkte Filter des Geräts bleibt dabei unberührt; der erste Klick in der Legende („Alle zeigen“ oder ein Chip) nimmt den Parameter weg und zeigt wieder, was das Gerät sich gemerkt hat. Der Aufklapper einer Veranstaltung führt mit seinem Weg zur Pflege des Stundenplans (/stundenplan/einrichten, Anschluss stundenplan.pflegeweg), die als Zeile Stundenplan auch im Bogen von „Kalender einrichten“ steht.
Lernzeiten und Sport der Woche (seit 16.10.2026, KN-261014-woche-bild)
Was früher über dem Wochenraster des Stundenplans stand, steht jetzt im Kalender: der Wochenstand der Lernzeiten (geplant, gelernt, was fehlt; ein Klick führt zu „Einstellungen › Lernzeiten“) und die Trainingszeile mit Strähne und je einem Haken für jeden Sporttermin. Breit stehen beide in der Seitenspalte unter der Legende, schmal unter dem Blatt. Sie zählen immer für die laufende Woche, gleich welchen Zeitraum das Blatt zeigt. Ohne Lernzeiten fehlt der Wochenstand, ohne Sport die Trainingszeile; ohne beides steht nichts da. Ein Haken lädt nur diesen Baustein neu; eine Änderung im Blatt lädt ihn mit (Anschluss stundenplan.Wochenstand).
Einen Termin anlegen (seit 21.09.2026, S-calendar)
Im Anlegefach des Rahmens, aufgeklappt über „Termin" oder über „Neu anlegen“ → „Termin“ in der Kopfleiste; auf beiden Wegen steht der Zeiger im Titel, auch wenn der Kalender schon offen war. Vier Angaben: Titel, Tag, Beginn und Ende, Ort — und seit dem 16.10.2026 die Wiederholung.
Eine Wiederholung macht aus dem Termin eine Serie (BE-261011-wiederkehrende-termine, Bens Rückmeldung vom 08.10.2026: Sport soll nicht mehr als Veranstaltung im Stundenplan sitzen müssen). Die Auswahl steht hinter dem Ort: einmalig (Vorgabe), wöchentlich, täglich, monatlich, jährlich. Erst mit einer Wiederholung erscheint das Feld Letzter Tag der Serie (leer heißt ohne Ende), bei „wöchentlich“ darunter die Zeile An diesen Wochentagen mit einem Kästchen je Tag von Montag bis Sonntag, vorgewählt der Wochentag des gewählten Tages, solange niemand einen anderen anklickt. Gespeichert wird dieselbe Regel an life.events wie seit BE63 unter „Leben“, also geht die Serie wie jede andere ins Blatt, in heute, ins Briefing und, wo eingeschaltet, als ein Termin mit RRULE nach draußen.
Der erste Termin ist immer ein Vorkommen. Wer an einem Mittwoch „Mo und Do“ wählt, bekommt den Donnerstag als ersten Termin, und das Fach sagt es: „Der erste Termin der Serie ist am …“. Ein Beginn, den die eigene Regel nicht trifft, liest jeder Kalender anders. BYDAY steht nur in der Regel, wenn mehr als der eine Wochentag des Beginns gewählt ist — so sieht eine Serie gleich aus, ob sie hier oder unter „Leben“ entstand (calendar/shared/terminserie.ts). Kein Wochentag, ein letzter Tag vor dem ersten Termin oder einer, der kein Tag ist, legt nichts an; das Fach nennt den Grund. Ein einzelnes Vorkommen verlegen oder ausfallen lassen geht weiter über „Dort bearbeiten“ im Aufklapper, im Vorkommenfach unter „Leben“ (BE63).
Warum das hier stehen muss. Ein Kalender, in dem man keinen Termin anlegen kann, ist eine Anzeige. Wer bis dahin etwas eintragen wollte, musste nach /life wechseln — und bekam dort ein Ereignis, das jetzt beginnt: Das Formular setzt startsAt auf den Augenblick des Klicks. Für etwas, das man nachträglich festhält, ist das richtig; für einen Termin am Donnerstag ist es unbrauchbar.
Deshalb steht hier die Zeit im Mittelpunkt und nicht die Person oder die Art. Wer ein Ereignis mit Personen verknüpfen will, tut das weiterhin in /life; der Termin ist danach derselbe — es ist dieselbe Zeile in life.events.
Ohne Uhrzeit ist es ein Tag. Kein eigener Haken dafür: Ein leeres Uhrzeitfeld sagt schon, was gemeint ist, und ein Haken, der dasselbe noch einmal fragt, ist eine Gelegenheit, sich zu widersprechen. Ein Ganztagstermin wird auf zwölf Uhr gelegt, nicht auf Mitternacht — ein Zeitstempel auf Mitternacht wird eine Schicht weiter mit den Feldern einer anderen Zone gelesen und ist dann der Vortag.
„22:00 bis 01:00" ist die Nacht und kein Tippfehler. Ein Ende vor dem Anfang wandert auf den nächsten Tag, statt einen Termin von minus einundzwanzig Stunden zu ergeben.
Die Uhrzeit gilt in der Zone des Nutzers, nicht in der des Browsers: gerechnet wird mit ausZone (calendar/shared/terminzeit.ts, neun Zusicherungen). Wer in Berlin wohnt, in Tokio sitzt und „14:00" einträgt, meint vierzehn Uhr in Berlin — sonst hätte die Einstellung keinen Zweck.
Der Tag bleibt nach dem Anlegen stehen, der Titel nicht: Wer einen Termin für den Donnerstag einträgt, trägt oft gleich den zweiten für denselben Tag ein.
Steht der Schalter Ereignisse aus, sagt das Fach es unter dem Knopf: Der Termin steht dann in Denotato, aber in keinem Google-Kalender — und der nächste Abgleich nähme ihn dort sogar wieder heraus. Das gehört unter den Knopf und nicht in eine Fehlermeldung hinterher.
Seit dem 14.10.2026 warnt das Fach vor einer Überschneidung (BE16, S-calendar 6), bevor angelegt wird: „Überschneidet sich mit „Analysis I“ (10:00).“ Geprüft wird gegen das, was der Schirm geladen hat — eigene Termine, Stundenplan, Spiegel —, mit derselben Rechnung wie die Kollision im Raster (anlegekollisionen, calendar/shared/stundenraster.ts): Berühren ist keine Überschneidung, ein fehlendes Ende zählt als Mindestdauer, Ganztägiges kollidiert mit nichts. Angelegt wird trotzdem; die Warnung hält nicht auf. Ganztägiges am gewählten Tag nennt das Fach seit dem 15.10.2026 leise (W8): „An diesem Tag steht ganztags: Umzug.“ Fällige To-dos, Fristen und Tageszusammenfassungen belegen keinen Tag und bleiben draußen.
Ein Termin in einem Satz (seit 16.10.2026, KN-261015-termin-satz)
Über den vier Angaben steht ein Feld „In einem Satz: Do 14 Uhr …“ mit dem Knopf Ausfüllen (oder der Eingabetaste). „Do 14 Uhr Sprechstunde Raum 3“ füllt Titel, Tag, Beginn und Ort aus; darunter steht „Aus dem Satz ausgefüllt — bitte prüfen.“ Angelegt wird erst mit „Anlegen“ — der Satz schreibt nichts (Befunde B15). Was der Satz nicht sagt, bleibt stehen, wie es war.
Erst lesen Regeln (@shared/handlers/zeit/terminsatz.ts): Datum („3.11.“, „20.11.2026“, „2026-12-01“), Wochentag („Do“, „donnerstags“) und „heute“, „morgen“, „übermorgen“; Uhrzeit und Spanne („14 Uhr“, „9.30“, „10–12“, „von 10 bis 12 Uhr“); Ort nach „Raum“, „Hörsaal“, „HS“, „SR“, „@“ oder „online“. Ein Wochentag meint den nächsten, heute eingeschlossen. Finden die Regeln weder Tag noch Zeit, fragt das Fach den Begleiter (Anlass „Termin aus einem Satz“, POST /api/life/calendar/satz/lesen, MCP kalender_satz_lesen); dann steht da „Vom Modell ausgefüllt — bitte prüfen.“ Mit geht nur der Satz und der heutige Tag. Ohne Begleiter, Schlüssel oder Budget sagt eine Zeile, warum, und das Formular bleibt bedienbar.
Beginn, Strich und Ende stehen am Telefon in einer Zeile (B15); bis zum 16.10.2026 brach das Ende allein um.
Lernblöcke vom Begleiter (seit 07.10.2026, KI-261007-planen-vorschlaege)
Bestätigt man die Karte „Lernblöcke“ des Begleiters, stehen die Blöcke als gewöhnliche Termine „Lernen: Prüfung · Thema“ im Blatt — kein eigenes Aussehen, keine eigene Kategorie: Verschieben und Löschen gehen wie bei jedem Termin. „Zurücknehmen“ an der Karte legt sie in den Papierkorb, aus dem man sie wie jeden Termin wiederherstellt. Ein Termin aus einem Abonnement wird dabei nie angefasst.
Nach draußen (seit 21.09.2026)
Die dritte Richtung. Oben schreibt Denotato nach Google, darüber liest es fremde Kalender herein — hier abonniert ein fremdes Programm Denotato. Kein Konto, keine Einrichtung, eine Richtung: eine geheime Adresse, die man in iPhone, Thunderbird oder Google einträgt, und darunter ein Strom im iCalendar-Format.
Es gibt keine Adresse, bevor jemand eine will. Ein Konto ohne Klick hat keine Zeile in life.calendar_exports — also nichts, was jemand erraten könnte. Eine Adresse auf Vorrat wäre ein Geheimnis, von dem ihr Eigentümer nichts weiß.
Die Adresse ist zweiteilig, und das hat einen Grund: Der vordere Teil ist eine Kennung und kein Geheimnis, er sucht die Zeile; der hintere ist das Geheimnis und wird mit timingSafeEqual verglichen, also in gleichbleibender Zeit und außerhalb der Datenbank. Ein Suchen nach dem Geheimnis selbst liefe über einen B-Baum, und der vergleicht Zeichen für Zeichen.
Jeder Fehlschlag sieht gleich aus: unbekannte Kennung, falsches Geheimnis, entzogenes Merkmal — dreimal 404 mit leerem Rumpf. Ein Unterschied wäre die Auskunft, dass es diese Kennung gibt.
Zwei der drei Schalter sind aus. Der Vorgang BE12 warnt ausdrücklich: „Fristen und Prüfungen sagen mehr über einen Menschen, als ihm beim Abonnieren bewusst ist." Was von selbst hinausgeht, ist deshalb das Sparsamste, das noch einen Kalender ergibt — die Veranstaltungen. Alles Weitere ist ein Klick, und der Klick ist die Zustimmung. Geburtstage gehen gar nicht hinaus, auch nicht mit allen drei Schaltern: Das sind Daten anderer Menschen, und ihre Preisgabe ist nicht die Entscheidung dessen, der die Adresse verteilt.
Veranstaltungen behalten ihre Uhrzeit — seit dem 23.09.2026 auch im Abgleich mit iCloud und Google (F61, Bens Befund K2). Bis dahin brachte der gemeinsame Sammler Ereignisse auf ganze Tage, und Bens erste Vorlesung stand in iCloud von Mitternacht bis Mitternacht und ohne Ort. Jetzt liest der Sammler all_day und location, rechnet Tag und Uhrzeit in der Zone des Kontos, und CalDAV schreibt DTSTART/DTEND in UTC samt LOCATION; Google bekommt dateTime und location. Die Beschreibung sagt „Vor Ort" oder „Online" statt irl. Serien mit Uhrzeit gehen seit BE37 als Wanduhrzeit mit TZID und VTIMEZONE hinaus, auch über die Zeitumstellung (BE59, Punkt 84 unter „Was fehlt“); Serien ohne Uhrzeit bleiben ganztägig. Prüfungen und Fristen sind in Denotato ohnehin Tagesdaten und gehen als Ganztagstermine hinaus.
Jeder Termin bringt einen Wecker mit (seit 22.09.2026). Wie lange vorher, sagt „Erinnerung (Minuten vorher)" weiter oben — dieselbe Zahl, die bis dahin nirgends wirkte. Geschrieben wird ein Alarmteil (BEGIN:VALARM) mit ACTION:DISPLAY, dem Titel als Beschreibung und einem Auslöser relativ zum Beginn (TRIGGER;RELATED=START:-PT1H30M für neunzig Minuten vorher). Null Minuten werden zu TRIGGER;RELATED=START:PT0S ohne Vorzeichen — „im Augenblick des Termins", nicht „minus nichts". Wer nie Einstellungen gespeichert hat, bekommt keinen Wecker: keine Zeile in life.calendar_settings heißt, dass niemand danach gefragt hat, und ein Kalender, der ungefragt piept, ist ein Ärgernis. Eine eigene Spalte auf life.calendar_exports gibt es dafür nicht, weil „wie lange vorher möchte ich Bescheid wissen" eine Antwort ist und nicht zwei.
Ein Klick statt eines Kopiervorgangs. Unter der Adresse steht „Im Kalenderprogramm abonnieren" — dieselbe Adresse, nur mit webcal:// davor. Das Schema kennt jedes verbreitete Kalenderprogramm, und es reicht die Adresse an den eingerichteten Kalender weiter, statt sie im Browser zu öffnen; wo es nicht greift, steht das Kopieren unverändert daneben. Der Verweis trägt rel="noreferrer" und kein target: Die Adresse ist das Geheimnis, sie hat in keinem Verweisgeber etwas zu suchen. Umgerechnet wird in calendar/shared/webcal.ts (sechs Zusicherungen), und umgeschrieben wird nur, was mit http oder https anfängt — der Schirm soll nichts anbieten, was er nicht selbst gebaut hat.
Eine Bremse steht davor (seit 22.09.2026, S-calendar). Dies ist der einzige Weg in Denotato, der ohne Sitzung auskommt — ein Kalenderprogramm hat keine —, und er war bis dahin ungezähmt. Zwei gleitende Eimer über eine Stunde: sechzig Abrufe je Kennung, hundertzwanzig je Adresse. Die sechzig sind einmal in der Minute; kein Kalenderprogramm fragt so oft — iOS lässt als engste Wahl fünf Minuten zu, Thunderbird eine halbe Stunde, Google Stunden —, und sie lassen mehrere Geräte an derselben Adresse nebeneinander arbeiten. Der zweite Eimer beantwortet das Raten: Wer je Kennung sechzigmal dürfte, dürfte mit tausend erfundenen Kennungen sechzigtausendmal.
Drei Feinheiten, und jede hat ihren Grund. Gezählt wird beim Betreten, also vor jeder Abfrage — wer erst hinterher zählt, hat eine Grenze für Gleichzeitigkeit und keine für die Rate. Der Eimer hängt an der Kennung und nicht am Konto, weil zum Zeitpunkt des Klopfens noch kein Konto feststeht; es festzustellen hieße, die Datenbank zu fragen, also genau das, was die Bremse vermeiden soll. Und deshalb füllt sich der Eimer auch für Kennungen, die es nicht gibt — eine erfundene Adresse wird genauso gebremst wie die richtige, und das „später" sagt so wenig wie die 404.
Gebremst wird mit 429 und einem Retry-After in Sekunden, das sich nach dem ältesten Klopfer richtet: Wer den neuesten nähme, schickte ein Kalenderprogramm eine ganze Stunde weg, obwohl in einer Minute etwas frei wird. Der Rumpf ist leer und Cache-Control: no-store, private verhindert, dass ein Zwischenspeicher das „später" festhält. Von der eigenen Maschine bremst nichts — die Nachweiskette kommt von dort und holt denselben Kalender in einem Lauf ein Dutzend Mal.
Die Rechnung steht als reine Funktion in calendar/shared/abrufbremse.ts (zehn Zusicherungen, Uhr als Parameter, damit „genau an der Grenze" ohne Warten prüfbar ist); die beiden Karten liegen in calendar/server/ausgabe.ts und werden ab fünfhundert Einträgen durchgekehrt, damit die Karte nicht wächst, solange jemand Kennungen erfindet.
Geschrieben wird der Strom von Hand (packages/plugins/src/calendar/shared/icsSchreiben.ts), ohne Paket und nach RFC 5545: Zeilen auf 75 Oktett gefaltet — nicht 75 Zeichen, sonst zerbricht der erste Umlaut —, CRLF überall, Sonderzeichen entkommen, Ganztagstermine als Datumswert, Zeitpunkte mit der Zone aus zeit.zone. Die Zonendefinition liegt bei und wird aus Intl abgelesen statt aus einer Tabelle, die vom Tag ihrer Entstehung an veralten würde.
Bausteine (seit 20.10.2026, E-261020-umzug-kalender, E-261020-umzug-bausteine)
Blatt und „Kalender einrichten“ zeichnen ihre Teile aus den gemeinsamen Bausteinen statt aus eigenen Nachbauten. Alle Überschriften beider Schirme sind der Abschnittstitel, halbfett; die Frage des Bogens stand vorher in der fetten Vorgabe des Browsers.
| Stelle | Bausteine |
|---|---|
| Blatt | Sprungfeld „Zu welchem Tag“ als Feldhülle mit Feld; Monatsname als Abschnittstitel (h3, groß); Kalenderwoche und Zeitspanne als Nebentext |
| Termin anlegen | Zeilenwort und „bis“ als Nebentext; der Tagknopf bleibt eigen, weil seine Farbe Inhalt ist |
| Termin im Blatt | Beschriftungen als Nebentext; der Weg zur Quelle als Knopf (geist), ohne Rand, Rundung md statt Pille |
| Legende und Vorlagenangebot | Satz der Legende als Nebentext; im Angebot der Punkt wie der Tupfen der Legende, Titel als Abschnittstitel, Nebentext |
| Einrichtungsbogen | Zeilenliste und Zeile; Feldhülle; Probetag-Leiste auf Fläche (papier); die Verweise als Textknopf, sie sehen aus wie „Ändern“ daneben |
| Abonnierte und fremde Kalender | Zeilenliste statt eigener Linien, Nebentext; „Datei übernehmen“ als Knopf (sekundär) |
| Nach draußen | Kalenderadresse als Identifier auf Fläche (papier), klein und schwach; der webcal-Verweis als Knopf (sekundär) |
| Kategorien | Kachel als Fläche (rahmen), Name als Abschnittstitel, Marken als Badge ohne Kartongrund, Felder in Feldhülle, kleine Texte als Nebentext |
| Zuordnung | Zeilenliste statt eigener Linien, Nebentext, Feldhülle |
| Was geschrieben wird | Feldhülle; die Zieltabelle als Datengitter mit Rahmen und Zelllinien |
Sichtbar anders als vorher: Nebenzeilen und Feldbeschriftungen in xs statt sm; Kacheln und Eingabefelder mit Rundung md statt lg und mit Hover- und Fokusrand; Listenzeilen mit der Mindesthöhe der Zeile. Eigen bleiben der Weg für den Apple-Kalender (Fließtext) und die Farbwahl (Farbe ist Inhalt).
Was man tun kann
| Element | Was passiert |
|---|---|
| Mit Google verbinden / Mit iCloud verbinden | Seit dem 15.10.2026 (KN-261015-abo-zuerst, Befund B14) steht eine Verbindung, die die Instanz nicht anbietet — weder verbunden noch mit Zugangsdaten des Betreibers noch über die Zugangsdaten eintragbar —, gar nicht mehr da; bietet sie keine, sagt das ein Satz, und „Trennen steht unter …“ erscheint nur, wenn etwas verbunden ist. Sonst steht je Anbieter und nur, wenn dieser Anbieter nicht verbunden ist. Ein Merkmalsdienst (iCloud) sagt stattdessen, wo man ihn einträgt (seit 22.09.2026, B2) — seit dem 13.10.2026 als Link „Einstellungen › Zugangsdaten“ auf /settings?a=zugaenge, ebenso der Satz, wo man trennt; vorher stand der Pfad als Text da (KN-261013-anschluss-einheitlich). Seit dem 15.10.2026 (KN-261015-kalender-ausnahme) fragt die nicht verbundene CalDAV-Zeile zuerst nach dem Bedürfnis, weil Apple keinen Anmeldeweg anbietet: „Was brauchst du von deinem Apple-Kalender?“ mit zwei Auswahlen — Apple-Termine hier sehen und Auch Denotato-Termine in Apple sehen. Beim Lesen sagt ein Satz, was das Abonnement nicht kann (Denotato-Termine erscheinen nicht in Apple, Änderungen kommen verzögert, der Kalender muss öffentlich freigegeben sein), empfiehlt trotzdem die Verbindung und verweist mit „abonniert stattdessen“ auf ?funktion=abonnieren. Nach jeder Wahl stehen zwei Schritte (App-Passwort erzeugen; Apple-ID und Passwort unter „Einstellungen › Zugangsdaten“ eintragen) und als Hauptknopf der Tiefenlink „App-Passwort bei Apple erzeugen“ (neuer Tab, Adresse aus dem Register). Darunter immer „Die KI fragen“: Er öffnet die Schnellsuche im Fragemodus mit einer fertigen Frage zum Weg und stellt sie gleich (nur mit Begleiter und Studium) Fehlten der Instanz die Google-Zugangsdaten (verbindbar: false), stand vom 11. bis 15.10.2026 statt des Knopfs der Satz, dass das der Betreiber einrichtet (F-261011-zugaenge-ohne) |
| Zustand neu holen | fragt die Verbindungen noch einmal ab, ohne die Seite neu zu laden; seit dem 15.10.2026 ein Nebenknopf (KN-261015-abo-zuerst: ein Hauptknopf je Schirm). Ebenso „Erst durchrechnen“, „Datei übernehmen“ und „Jetzt lesen“; „Jetzt abgleichen“ ist nur Hauptknopf, wenn ein Konto verbunden ist |
| Einrichten | Knopf im Kopf des Kalenders; führt auf /calendar/einrichten (seit 09.10.2026, W-261009-kalender-einrichtung) |
| Zum Kalender | Knopf im Kopf der Einrichtung; führt zurück aufs Blatt |
| Bearbeiten (Legende) | im Menü einer eigenen Kategorie, in der Spalte als Knopf am Ende der Zeile; führt in die Einrichtung und schlägt dort genau diese Kategorie zum Ändern auf (seit 09.10.2026) |
| Kategorie an- und ausblenden | ab 1200 Pixeln mit dem Farbkasten in der Spalte links (seit 09.10.2026, W-261009-kalender-wie-google; bis zum 18.10.2026 ab 900 Pixeln); schmaler bei eigenen Kategorien über „Ausblenden“ bzw. „Einblenden“ im Menü des Legendeneintrags, im Rückfall mit einem Klick (seit 09.10.2026); das blendet ihre Termine aus dem Raster, dem Monat und der Agenda aus. Die Auswahl bleibt erhalten — im localStorage dieses Geräts (denotato.kalender.verborgen), also je Bildschirm verschieden und nie auf dem Server (seit 22.09.2026). Der Klick wirkt — seit dem 23.09.2026 (G1). Die Vorschauzeile aus LIFE_CALENDAR trägt kategorieId und quelle; Legende und Filter rechnen denselben Schlüssel. Gemessen am 23.09.2026 für ein eingerichtetes Konto: fünf Legendenschlüssel, drei belegte Filterschlüssel, Schnittmenge drei — vorher null. Zwei der fünf Kategorien haben im Fenster keinen Termin; das ist Bestand und kein Fehler. Im Rückfall auf die festen Arten wirkt er wie bisher. Siehe Punkt 64 |
| Alle zeigen | erscheint nur, solange etwas ausgeblendet ist, und nennt die Zahl |
| Zu welchem Tag | springt in der gewählten Ansicht auf ein Datum; ein leeres Feld setzt nichts zurück |
| Suche | filtert Titel und Beschreibung, ohne Groß- und Kleinschreibung, vor der Zählung im Monatsfeld — sonst stünde hinter „+2" etwas, das der Begriff nicht trifft |
| Erst durchrechnen | ein Probelauf: rechnet den Abgleich vollständig durch und schreibt nichts — weder nach draußen noch in Denotato (seit 22.09.2026, B-35). Läuft er, heißt der Knopf „Rechnet durch …". Seit dem 23.09.2026 (N148) rechnet er den Stundenplan mit — je Kategorie und je Zielkalender. Seit BE37 schreibt ihn auch ein echter Lauf, aber nur über eine Kategorie, die seit dem 24.09.2026 freigegeben ist (STUNDENPLAN_FREIGABE_AB); eine ältere Freigabe galt einem Probelauf, der ihn nicht schreiben konnte. Bis zur neuen Freigabe steht er als „zurückgestellt“ mit dem Grund „Stundenplan: Freigabe aelter als der Schreibweg — nach dem Probelauf neu freigeben (BE37)“, in der Tabelle je Zielkalender als „davon … Stundenplan, nicht geschrieben“ und darunter „nach Freigabe: …“. Das hält der Abgleich selbst fest (gleicheAb), nicht der Knopf. In einem Konto ohne Kategorien hat der Stundenplan keinen Zielkalender (N157); er wartet dann als Hinweis „Stundenplan: ohne Kalenderkategorien hat er keinen Zielkalender — erst eine Kategorie anlegen (F88): … Eintraege warten.“ und zählt seit dem 24.09.2026 nicht mehr als Fehler — sonst entwarnte das Störungsbuch eine behobene Störung des Anbieters nie (F88, B17). Die Fristen einer Prüfung warten dort ebenso, als Hinweis „Prüfungsfristen: ohne Kalenderkategorien haben sie keinen Zielkalender — erst eine Kategorie anlegen (BE38): … Eintraege warten.“ (seit 26.09.2026). Die Moodle-Fristen rechnet der Knopf nur mit, wenn ihr Schalter an ist; über die Route und kalender_abgleich_jetzt nimmt ein Probelauf sie mit mitMoodle: true auch bei ausgeschaltetem Schalter mit (seit 15.10.2026, BE47), am Schirm gibt es dafür keinen Haken |
| Abgleich einschalten | schaltet den Sammler an |
| Einstellungen speichern | schreibt Vorlauf, Erinnerung, Modus. Läuft es, heißt der Knopf „Speichert …"; scheitert die Anfrage ganz (Netz weg, Sitzung abgelaufen), ist er danach wieder frei und oben steht „Fehler bei der Anfrage aufgrund eines unbekannten Fehlers" (seit 23.09.2026, A30) |
| Jetzt abgleichen | führt den Abgleich sofort aus. Seit dem 23.09.2026 (N148) schreibt er nur für freigegebene Kategorien: Eine Kategorie, die nach draußen schreiben soll, aber keine Freigabe trägt, wird geschont — für sie wird nichts geschrieben und nichts gelöscht, und der Bericht nennt sie als „angekündigt“. Der Knopf ist nicht mehr gesperrt (seit 22.09.2026, B2): Er hing an stand.verbunden, und das kannte nur Google — ein reiner iCloud-Abgleich war über die Oberfläche unerreichbar, obwohl der Server ihn kann. Was ohne jede Verbindung passiert, sagt der Server in drei unterscheidbaren Meldungen. Die drei Knöpfe teilen sich seit dem 23.09.2026 einen Riegel (useBusyLock, A30): Ein zweiter Klick während des Laufs geht ins Leere, und ein Lauf, der wirft statt zu antworten, gibt alle drei wieder frei und setzt die Fehlerzeile oben. Bis dahin blieben sie nach so einem Fehlschlag bis zum Neuladen grau — nachgewiesen in Kalendermenue.test.tsx, der gegen den alten Stand rot war. Seit dem 24.09.2026 (B17) bucht er ins Störungsbuch wie der Zeitgeber: Ein Abbruch steht als kalender-google oder kalender-icloud beim Konto — in der Übersicht und bei der Betriebswache —, ein Lauf ohne Fehler entwarnt sofort — wer nach der Mail der Zugangswache trennt, neu verbindet und von Hand abgleicht, sieht die Störung gleich verschwinden und nicht erst nach dem nächsten Zeitgeberlauf. Ein fehlender Zugang und „Erst durchrechnen“ buchen nichts. Bis dahin buchte nur der Zeitgeber |
| Woche · Tag · Monat · Agenda | schaltet das Blatt um, ohne den Zeitpunkt zu verlieren. Die Wahl bleibt erhalten — localStorage, Schlüssel denotato.kalender.ansicht (seit 22.09.2026, Punkt 34) |
| Winkel zurück / vor (gezeichnet seit 10.10.2026, vorher „‹“ und „›“ aus der Schrift) | blättert um das, was die Ansicht zeigt — einen Monat, sieben Tage, einen Tag |
| Heute | springt auf den heutigen Tag zurück, in jeder Ansicht |
| Wischen (Telefon) | blättert im Monat, in der Woche und im Tag vor oder zurück — ab einem Viertel der Breite oder mit Schwung (seit 07.10.2026). Ein Wisch, der in den ersten 24 px am linken Rand beginnt, blättert nicht: Der Rand gehört dem Zurück des Browsers (BW-261007-gesten) |
| Termin ziehen / am unteren Rand verlängern | in Woche und Tag, mit Maus oder Stift, nur an eigenen einzelnen Terminen mit Uhrzeit. Rastet auf die Viertelstunde ein und bleibt gestrichelt als Vorschlag stehen (seit 07.10.2026) |
| Verlegen / Verwerfen | in der Leiste unten am Blatt: schreibt den Vorschlag oder lässt den Termin, wo er war |
| Zurücknehmen | nach dem Verlegen in derselben Leiste, ebenso mit Strg+Z oder über die Kopfleiste: legt den Termin auf seine alte Zeit zurück |
| Termin (Anlegefach) | legt einen Termin an: Titel, Tag, Beginn/Ende, Ort — ohne Uhrzeit gilt der ganze Tag |
| Termin anklicken | öffnet die Einzelheiten als Aufklapper am Termin; derselbe Termin noch einmal, Esc, das Kreuz oder ein Klick daneben schließen ihn, der Fokus kehrt auf den Termin zurück (seit 09.10.2026); im Monatsraster führt der Titel weiterhin unmittelbar zur Quelle |
| Einen Posten anklicken | in den Einzelheiten einer Tageszusammenfassung: führt zu der Aufgabe, die fällig ist — ein To-Do nach /tasks?id=… mit hervorgehobener Zeile, eine Wiedervorlage nach /tutor (seit 23.09.2026, H2) |
| Zeiger über einer Zusammenfassung | im Monat und in der Agenda steht die ganze Liste im Zeigerhinweis, eine Zeile je Posten — der billigste Weg an das, was der beschnittene Titel nicht mehr zeigt (seit 23.09.2026, H2). Ein Zeigerhinweis setzt einen Zeiger voraus; am Telefon führt der Weg über das Fach |
| Umhängen nach … / Ausblenden / Wieder wie gerechnet | in den Einzelheiten eines Termins: hängt diesen einen Tag in eine andere Kategorie, blendet ihn aus, oder nimmt beides zurück. Es ändert nur diesen Termin, nicht die Regel dahinter (…UEBERSTEUERUNG, seit 22.09.2026) |
| Kategorie anlegen / Ändern | Jede Kachel nennt die Kategorie mit dem Farbtupfen vor dem Namen, ebenso jede Regel und Ableitung vor ihrem Satz (seit 10.10.2026 statt eines Streifens links, ES-261009-farbige-seitenstreifen, E11). Name, Farbe, Vorgabeflagge, sichtbar, eingeschaltet, im .ics-Strom, nach draußen schreiben. Der Zielkalendername wird abgeleitet (<Instanzname> · <Name>) und nicht abgefragt. Seit dem 11.10.2026 (VA-261010-gespeicherter, Wanderung 288) speichert die Kategorie nur den Rest nach dem Vorsatz („Klausuren“); die Kachel, die Löschwarnung und der Hinweis „Der Kalender heißt draußen“ setzen den Instanznamen aus der Verwaltung davor („Denotato · Klausuren“). Ein vor dem 11.10.2026 angelegter Kalender heißt beim Anbieter weiter „GOLD · …“ und wird wiedergefunden, ohne dass ein zweiter entsteht. Einschalten ist seit dem 23.09.2026 (N148) noch nicht Schreiben: Wer „Nach draußen schreiben" setzt — bei einer neuen oder einer bestehenden Kategorie — oder einer schreibenden Kategorie ein neues Ziel gibt (eigener Kalender statt mitschreiben, ein anderer Zielkalender, ein anderer Sammler), bekommt eine angekündigte Kategorie; ein neues Ziel nimmt die Freigabe auch jeder Kategorie, die in diese sammelt. Das setzt der Server zurück, der Schirm zeigt es auf der Kachel |
| Freigeben | steht auf der Kachel einer Kategorie, die nach draußen schreiben soll und nicht freigegeben ist, daneben die Marke „angekündigt, nicht freigegeben" und der Satz „Vor dem Freigeben „Erst durchrechnen" ansehen: Der Probelauf nennt, was diese Kategorie wohin schriebe („nach Freigabe"). Bis zur Freigabe schreibt und löscht der Abgleich für sie nichts, auch nicht in ihrem Zielkalender. Die Freigabe gilt danach für alles, was hierher fällt, auch aus neuen Regeln; nur ein neuer Zielkalender nimmt sie wieder." (der letzte Satz seit dem 24.09.2026, N225, BE55; von N149 bis dahin: „Eine neue oder geänderte Regel, die Termine hierher lenkt, nimmt die Freigabe wieder weg.") (der Teil ab „auch nicht“ seit der Nachbesserung vom 23.09.2026). Ein Klick gibt frei (LIFE_CALENDAR_KATEGORIE_FREIGEBEN, seit 23.09.2026, N148); der nächste Abgleich — auch der Zeitgeber — schreibt sie hinaus |
| Freigabe zurücknehmen | steht auf der Kachel einer freigegebenen, schreibenden Kategorie (Marke „freigegeben"). Danach schont der Abgleich sie: nichts geschrieben, nichts gelöscht — was draußen steht, bleibt stehen. Seit der Nachbesserung vom 23.09.2026 gilt das auch für Termine, deren Quelle inzwischen weg ist (gelöschtes To-Do, verstrichene Frist, Ereignis aus dem Fenster): Der Zielkalender einer angekündigten Kategorie ist eingefroren, aus ihm wird nichts gelöscht und nichts hinausgezogen. Vorher räumte der Lauf solche Termine dort weg, obwohl die Kachel „löscht nichts“ sagte. Wer die Termine draußen weghaben will, nimmt stattdessen „Nach draußen schreiben" weg. Fehlt der Instanz die Freigabespalte (Wanderung 94), gibt es beide Knöpfe nicht, und unter den Kacheln steht, dass jede schreibende Kategorie sofort schreibt |
| ↑ / ↓ | verschiebt eine Kategorie in der Reihenfolge — eine Anfrage für die ganze Liste, nicht eine je Zeile |
| Wegtun | fragt nach und sagt vorher, wieviele Termine draußen daran hängen und wohin sie fallen: „Gelöscht wird keiner: Sie fallen auf deine übrigen Regeln oder auf die Vorgabe „…", wie ein Termin ohne Regel." Gewählt wird das seit dem 24.09.2026 nicht mehr (F87, N223). Der zweite Satz sagt, dass die Kategorie für 30 Tage in den Papierkorb kommt (Kontoknopf › Deine Daten) und ihre Regeln, Ableitungen und Übersteuerungen so lange mit ihr ruhen; ist die Freigabesperre an, sagt ein dritter: „Die übrigen Kategorien behalten ihre Freigabe: Was jetzt in sie fällt, schreibt der nächste Abgleich ohne neue Freigabe." (N225) — und, nur bei einer Kategorie, die nach draußen schreibt: „Holst du sie zurück, schreibt sie erst wieder, wenn du sie freigibst." Die Meldung danach nennt die Zahl und die Vorgabe. Fehlt Migration 122, sagt eine Warnung statt des Papierkorbs, dass die Regeln weitergreifen. Die Vorgabekategorie und die letzte lassen sich nicht wegtun |
| Farbe wählen | zehn Töne aus FARBAUSWAHL plus freie Hex-Eingabe; daneben ein Probestreifen je Szene (Nacht und Tag; der Tagstreifen zeigt den Ton so abgedunkelt, wie ihn die Tagszene malt, seit 29.09.2026, E11) und Warnungen bei Dubletten, zu ähnlichen Tönen und zu blassem Kontrast — Warnung, kein Riegel |
| Regel anlegen / Ändern / Löschen | Quelle, Kategorie, Filter, Zeitfeld, Verdichtung, Rang. Seit dem 15.10.2026 (BE47) gibt es die Quelle Moodle-Fristen mit den Filtern „Art der Aktivität“ und „Kurs“ (beide freie Eingabe) und dem Zeitfeld due_at; die Kategorie eines zugeordneten Kurses gilt vor jeder solchen Regel, wie beim Abo der Fremdkalender. „Termine verhindern" statt „zuordnen" schaltet auf die Quellen um, die der Tag wegnimmt. Der Hinweis darunter sagt seit dem 23.09.2026 auch, was ein freier Tag vom Stundenplan nimmt: ein vorlesungsfreier nur die Lehrveranstaltungen — Sport, Arbeit, Lernen und Sonstiges bleiben (Bens Entscheidung E2) —, ein Feiertag alles (C37, Christians Entscheidung N149); ausdrücklich eingetragene Vorkommen bleiben an beiden. Dasselbe sagt die Regel in der Liste: „Freie Tage verhindert an diesem Tag: Stundenplan (an Feiertagen alles, an vorlesungsfreien Tagen nur Lehrveranstaltungen)“ (verhinderteQuelle, calendar/shared/regeln.ts); bis C37 stand dort nur „(nur Lehrveranstaltungen)“, und das wäre am Feiertag eine falsche Auskunft. Gerechnet wird das in der Serie des Stundenplans (stundenplanserie), nicht in der Regel — siehe Punkt 103 |
| Ableitung anlegen | ein zweiter Termin vor oder hinter jedem Termin einer Kategorie — Dauer und Abstand trägt man ein, Denotato rechnet sie nicht |
| Löschen (Regel, Ableitung) | seit dem 23.09.2026 in zwei Klicks: der erste fragt, erst „ja, endgültig" löscht, „doch nicht" lässt sie stehen (Q09, N165). Regeln und Ableitungen haben keinen Papierkorb; bis dahin war ein Klick das Ende. Ein Fehlschlag geht wie vorher an die Meldung des Kalenders |
| Nehmen / Nein danke (Vorlagenangebot, seit 14.10.2026 über den Kacheln, seit 15.10.2026 über dem Bogen der Einrichtung) | übernimmt eine Vorlage als Kopie oder lehnt das Angebot ab. Beides setzt den Zeitstempel kalender.vorlage.gefragt; danach kommt es nicht wieder |
| In Denotato spiegeln (fremder Kalender) | schaltet, ob Denotato die Termine eines fremden Kalenders kopiert. Geschrieben wird dort nie. Bei einem .ics-Abo liest der Abruf die Termine immer mit; der Schalter entscheidet dort nur, ob sie erscheinen, und wirkt deshalb sofort (seit 24.09.2026, N216) |
| Kategorie (fremder Kalender) | ordnet alles aus diesem Kalender einer Kategorie zu — ein Abo ist seine Zuordnung, deshalb braucht es dafür keine Regel. Für ein .ics-Abo ist das seit dem 24.09.2026 der einzige Weg (N216): Die in BE41 geplante Route /abos/kategorie gibt es nicht, und setzeAboKategorie in abos.ts, das nie eine Route hatte, ist entfernt |
| Abonnieren | trägt eine .ics- oder webcal-Adresse ein und holt sie sofort einmal — wer eine Adresse eingibt, will wissen, ob sie taugt. Scheitert es, steht hinter der Meldung der Grund des Servers („… : länger als 2048 Zeichen“). Scheitert erst der Abruf oder die Spiegelung, steht das Abo trotzdem da und nennt den Grund an seiner Zeile, nie ein 500 (seit 24.09.2026, BE64). Ausnahmen einer Serie treffen ihr Vorkommen am Tag in der Zone des Termins, nicht an der Uhrzeit — AGNES/LSF schreibt sie um 14:00 UTC, gleich wann die Veranstaltung beginnt (BE65) |
| Datei übernehmen | lädt eine .ics-Datei in die Ablage (uploadFile, dieselbe wie unter „Dateien") und übernimmt sie dann als Abo — derselbe Leser, derselbe Vergleich wie bei einer Adresse. Über 5 MB (DATEI_ABO_HOECHSTENS_BYTE in calendar/shared/dateiabo.ts, dieselbe Zahl prüft der Server) weist der Schirm sie ab, bevor sie hochgeladen ist. Liest der Server sie nicht als Kalender, sagt der Schirm einen eigenen Satz, der von der Datei spricht; die Meldung des Servers spricht von einer Adresse. Bleibt aus, solange keine Datei gewählt ist (seit 24.09.2026, BE40) |
| Jetzt lesen | holt ein Abonnement außer der Reihe — nicht an einem Abo aus einer Datei, dort gibt es nichts nachzulesen |
| Pausieren / Fortsetzen | schaltet ein Abonnement still, ohne nachzufragen — der Zeitgeber lässt es aus, die Adresse und die Termine bleiben stehen; derselbe Knopf holt es zurück (seit 21.09.2026, BE11). Ein Abo aus einer Datei hat ihn nicht: Es ruht immer, und ein „Fortsetzen" daran versprach etwas, das es nicht gibt |
| Kündigen | fragt nach und nennt dabei, wieviele Termine mitgehen; ein Klick allein tut nichts. Seit dem 23.09.2026 fragt der gemeinsame Baustein Wegtun, Klasse endgültig: „ja, endgültig" / „doch nicht" statt „Wirklich kündigen" (Q09, N165); der Satz mit der Zahl steht weiter sichtbar daneben |
| Adresse erzeugen | legt die erste geheime Adresse an — vorher gibt es keine |
| Veranstaltungen · Fristen · Prüfungen | schalten sofort, ohne eigenen Speichern-Knopf; der nächste Abruf liefert schon das Neue. Die Rangfolge (festgehalten am 23.09.2026, Bens Befund N5): Der Strom liefert nach Art aus, nicht nach Kategorie. Je Art entscheidet in_ics_feed der lebenden Bestandskategorie (die mit legacy_kind); die drei Schalter an der Adresse sind nur der Rückfall — für ein Konto ohne Bestandskategorien und für eine Art, deren Kategorie stillgelegt oder weggetan ist. „Im eigenen .ics-Strom" an jeder anderen Kategorie (etwa „Allgemein" aus der Einrichtung) wirkt auf den Strom heute nicht. Geschrieben wird seit dem 22.09.2026 an beiden Stellen: life.calendar_categories.in_ics_feed der Kategorie mit dem passenden legacy_kind — das ist die Wahrheit, nach der der Strom geht — und life.calendar_exports.with_* als Rückfall für ein Konto ohne Bestandskategorien. Was der Haken zeigt, ist ebenfalls der wirksame Wert und nicht mehr die alte Zeile. Anmeldeschluss und Rücktrittsfrist haben keine Art und folgen im Strom dem Schalter und der Kategorie der Prüfungen (seit 26.09.2026, BE38) |
| Tagesrhythmus und Wege | seit 16.10.2026 (S-261014-kalender-gemeinsam, R2), Einstellung kalender.rhythmus.abgleich, Vorgabe aus. An: Die Adresse liefert Schlaf und Fertigmachen als Wochenserie je Wochentag (Kategorie „Tagesrhythmus“, die Kennung hängt an Art und Wochentag, nicht an der Uhrzeit) und die Wege der nächsten vierzehn Tage zu eigenen, gespiegelten und Stundenplanterminen mit erkanntem Ort (Kategorie „Wege“, Titel wie „Zuhause → Uni“). Gespeichert wird nichts; der nächste Abruf rechnet aus Rhythmus und Wegeplan neu. Ohne Rhythmus oder Wege kommt nichts dazu |
| Adresse kopieren | in die Zwischenablage, wenn der Browser sie hergibt; der Text ist ohnehin auswählbar |
| Im Kalenderprogramm abonnieren | öffnet dieselbe Adresse mit webcal:// davor — iPhone, macOS, Thunderbird und Outlook reichen sie an den eingerichteten Kalender weiter (seit 22.09.2026) |
| Adresse erneuern | fragt nach und erzeugt dann eine andere — jedes laufende Abonnement zeigt danach einen leeren Kalender |
| Zurückziehen | fragt nach und lässt danach keine Adresse zurück, auch keine neue. Die drei Haken stehen danach auf dem Wert, mit dem eine neu erzeugte Adresse ausliefern würde — die Kategorie überlebt das Zurückziehen. Bis zum 24.09.2026 kam hier fest „Veranstaltungen an, Fristen und Prüfungen aus“ zurück, die Vorgaben der Tabelle, auch wenn Veranstaltungen vorher aus standen (BE61). Ein Haken ohne Adresse ändert nichts, auch nicht an der Kategorie, und zeigt danach den unveränderten Stand |
Scheitert eine dieser Anfragen, bleibt der jeweilige Knopf bedienbar (F28b, 23.09.2026): Fremdkalenderliste, Kalenderabos, Kalenderverbindungen, Kategorienverwaltung, Regelverwaltung, Terminanlegen, Termineinzelheiten und Vorlagenangebot setzen ihren Laufmerker jetzt ebenfalls über useBusyLock, das ihn in einem try/finally wieder freigibt — „Abonnieren", „Kündigen", „Verbinden"/„Trennen", „Regel anlegen", „Termin anlegen" und „Nehmen"/„Nein danke" blieben vorher bis zum Neuladen gesperrt, wenn die Anfrage warf, statt einen Fehlertext zu liefern.
Woher die Daten kommen
/api/life/calendar/* — Zustand, Einstellungen, Vorschau, Abgleich. Google-Seite über sync/googleCalendar.ts.
Der Zustand überlebt einen Ausfall (seit 27.09.2026, L03, Grundsatz 33). Die Antwort von LIFE_CALENDAR liegt als Rückfall unter denotato.rueckfall.calendar.stand (beim Abmelden weg). Antwortet der Server nicht — ohne Netz oder bei stehendem Dienst —, zeigt der Schirm die Woche und die Einstellungen vom letzten Mal und darüber die Marke „Der Server antwortet gerade nicht — Stand von …" (bis zum 30.09.2026 „Der Kalender …" — aber es antwortet Denotato nicht, nicht der Kalender, und jeder andere Schirm sagt „Der Server"); der Fehler steht wie bisher im Kopf. Gab es noch keinen Stand, bleibt es beim Skelett. Die Kategorien fallen wie bisher auf die vier festen Arten zurück, das Vorlagenangebot erscheint nicht. Schreiben ohne Netz sagt „Ohne Verbindung nicht speicherbar".
Was eine Vorschauzeile trägt (LIFE_CALENDAR, Feld kommende): art · quelle · kategorieId · kategorie? · farbe? · titel · beschreibung · tag · quelleTabelle · quelleId · posten? · beginn · ende (die beiden mit ? fehlen, wenn das Konto keine Kategorien hat — Absatz „kategorie und farbe" darunter). quelle und kategorieId sind am 23.09.2026 dazugekommen (G1) und sind die beiden Felder, an denen Farbe, Legende und Filter hängen. Sie stehen nicht doppelt: art sagt, in welchen der vier alten Kalender ein Termin geschrieben würde, quelle sagt, woher er kommt — für eine Vorlesung sind das ereignis und stundenplan, und das erste ist nur die Anzeige (ANZEIGEART_OHNE_ART in kalender.ts): Seit N157 hat ein Stundenplantermin gar keine Art, sein Zielkalender kommt allein aus der Kategorie (BE37). beginn und ende sind Zeitpunkte in UTC; für den Stundenplan entstehen sie aus der Wanduhrzeit der Veranstaltung und der Zone des Kontos (wirksamerWert(userId, 'zeit.zone'), dann ausZone), weil eine Vorlesung um Viertel nach neun anfängt und nicht zu einem Zeitpunkt.
posten ist am 23.09.2026 dazugekommen (H2) und steht nur an einer Tageszusammenfassung. Es trägt je fälliger Sache titel · wiedervorlage · zeit (Ortszeit HH:MM oder null) · quelleTabelle · quelleId. Der Sammler behält diese Liste seit H1 (calendarCollector.ts, verdichte), und der Titel und die Beschreibung des Termins entstehen aus ihr — nach draußen geht nur der Text, in Denotato die Liste. Fehlt das Feld, ist das kein Fehler: Ein Termin, der keine Zusammenfassung ist, hat keine Posten, und ein Dienst, der älter ist als diese Zeile, schickt auch bei einer keine. Der Schirm zeigt dann die Beschreibung mit ihren Zeilenumbrüchen und sagt dazu, woran es liegt. Bis zum Abend des 23.09.2026 kam die Liste auch von einem neuen Dienst nie an: zuTerminzeile baut die Zeile Feld für Feld neu und ließ posten aus. Seitdem liest zuPosten sie mit (Punkt 106).
kategorie und farbe sind am 23.09.2026 dazugekommen (AP5, BE41): der Name der Kategorie zu kategorieId und ihre Farbe als #rrggbb — für ein Modell oder einen anderen Leser, der die Kategorienliste nicht geladen hat. Gerechnet wird nichts neu: kalenderStand lädt die Kategorienlage einmal (ladeKategorienlage), reicht sie dem Sammler durch (Vorschauzusatz.lage) und schlägt die Kennung, die der Sammler gesetzt hat, in derselben Lage nach (calendar/server/kategorieangabe.ts). Fehlen beide Felder, hat das Konto keine Kategorien — die Form von vorher; kategorie: null heißt „fällt in keine". Ein gespiegelter Termin ohne Kategorie trägt die Farbe seines fremden Kalenders (remote_color, über Vorschauzeile.fremdfarbe). Die Farbe ist die der eigenen Kategorie, nicht die des Sammelkalenders, in den eine shared-Kategorie schreibt — dieselbe, die der Schirm zeigt (farbeVon). Der Schirm liest die beiden Felder (zuTerminzeile, tolerant: fehlt oder kaputt heißt weglassen), färbt aber weiter aus seiner geladenen Liste (Punkt 104).
Eine ruhende Kategorie (aktiv: false) schreibt nichts: Ein Termin, der in sie fällt, entsteht nicht und steht deshalb nicht in kommende — ein gespiegelter schon, mit ihrem Namen und ihrer Farbe. Die Woche des Stundenplans nennt die ruhende Kategorie dagegen auch an einem Ereignis, weil es stattfindet (Punkt 107). Eine weggetane Kategorie ist keine: Hängt ein fremder Kalender noch an ihr, tragen seine Termine kategorieId: null, kategorie: null und seine eigene Farbe, und die Fremdkalenderliste nennt für ihn kategorieId: null (seit dem 23.09.2026, Punkt 108). Beides prüft verify:kalenderanbieter (Teil m, Fälle 7 und 8).
Gemessen am 23.09.2026: An dieser Route schneidet das Zod-Schema nichts ab. Die Gegenproben zu verify:kalenderanbieter (Teil m) haben die Zeilen für kategorie und farbe herausgenommen, danach die für quelle und kategorieId, und in der Woche des Stundenplans die für kategorie und farbe — alle Felder kamen trotzdem an. Eine verschlüsselte Antwort ist eine Zeichenkette, und an die legt Fastify kein Antwortschema an (D35). Die Zeilen stehen als beschriebener Vertrag. Wo ein Feld „lautlos leer" am Schirm ankam, lag es am Client: zuTerminzeile las posten nicht (Punkt 106).
Hinweis: Bis zum 23.09.2026 stand hier eine Warnung, die nicht stimmte:
defineResponseFieldsschneide ab, was nicht im Zod-Schema vonrouten.tssteht, und ein neues Feld am Server komme lautlos leer am Schirm an. Gemessen tut es das nicht (Absatz darüber); die Lücke beipostenlag im Client. Ein neues Feld gehört trotzdem ins Schema — als Vertrag, und weil D35 die Antworten einmal zur Laufzeit auf das Schema zuschneiden soll. Dann gälte die Warnung.
Der Stundenplan kommt über denselben Sammler, nicht über einen zweiten Anschluss. kalendervorschau nimmt seit dem 23.09.2026 einen Vorschauzusatz; { stundenplan: true } schaltet in sammleTermine den Zweig ein, der sammleStundenplantermine ruft. Weil dieser eine Serie liefert und die Vorschau einzelne Tage zeigt, entfaltet entfalteWochenserien (calendar/server/kalender.ts) sie über das Fenster: ein Vorkommen je Regeltag, Ausfalltage und — bei Lehrveranstaltungen — vorlesungsfreie Tage fallen heraus (eine Sportserie trägt an einem vorlesungsfreien Tag seit dem 23.09.2026 kein Ausfalldatum mehr, an einem Feiertag seit C37 wieder eines wie jede Vorlesung), ein verlegtes Vorkommen ersetzt das der Regel statt danebenzutreten. Die Rechnung dahinter steht rein in calendar/shared/serienvorkommen.ts und liest nur die Wiederholungsregel, die Denotato selbst schreibt (FREQ=WEEKLY;BYDAY=…[;INTERVAL=2][;UNTIL=…]); alles andere bleibt der eine Tag, der dasteht.
Der Abgleich sieht davon nichts. gleicheAnbieterAb und runKalenderAbgleich.ts bekommen weiterhin stundenplan: false — Kalendertermin.art hat für eine Veranstaltung keinen Wert, und wer den Schalter dort umlegte, schriebe 22 Vorlesungen als Ganztagstermine in ein echtes Apple-Konto. Jede Anfrage an einen Anbieter trägt eine Frist (seit 23.09.2026, A30). fetch wartet in Node ohne Angabe unbegrenzt, und darunter fängt nichts auf: Fastify setzt weder requestTimeout noch connectionTimeout. Ob es das soll, ist offen (A30, Schritt 3); den Abgleich finge requestTimeout ohnehin nicht, weil es in Node nur das Empfangen der Anfrage begrenzt. Die Grenze steht deshalb am Aufruf selbst: CALDAV_TIMEOUT_SECONDS (sync/caldav.ts) und GOOGLE_TIMEOUT_SECONDS (sync/googleCalendar.ts, auch beim Tausch des Codes im Rückruf, beim Auffrischen des Zugangs und beim Widerruf in verbindungenController.ts), ohne Angabe je 20 s; der gemeinsame Teil liegt in sync/zeitgrenze.ts. Zulässig sind 0,1 bis 300 s — die Obergrenze ist die Geduld von nginx vor /api/, und was darüber oder darunter liegt oder keine Zahl ist, ergibt die Vorgabe. Gerissen heißt es dann in life.calendar_accounts.last_error und im Bericht „Der CalDAV-Server hat nicht innerhalb von 20 s geantwortet (PROPFIND)." statt „The operation was aborted due to timeout", und der Fehler trägt Status 0 — „keine Antwort", nie 404. Nach dem ersten Schweigen fragt derselbe Lauf diesen Anbieter nicht noch einmal; jeder weitere Aufruf an ihn scheitert sofort mit dem Zusatz „Weitere Anfragen an ihn unterbleiben in diesem Lauf." Im Bericht erscheint das aber nur bei Anlegen, Ändern, Umziehen und Löschen selbst: Verstummt der Server erst, während der Abgleich vor dem Ändern oder Löschen die Marke eines Termins liest, steht dort irreführend „traegt draussen keine Marke dieses Kontos" (Punkt 77). Ein Netzfehler wie ECONNREFUSED setzt den Riegel nicht — er kommt ohnehin sofort. Nachgewiesen in npm run verify:caldav: für CalDAV gegen einen Server, der annimmt und schweigt, für Google gegen einen nachgebauten fetch, der nie antwortet.
Die vierzehn Kategoriewege (SCHEMA §10.1), seit dem 22.09.2026 alle gebaut und alle von der Oberfläche gerufen: LIFE_CALENDAR_KATEGORIEN · LIFE_CALENDAR_KATEGORIE_SPEICHERN · LIFE_CALENDAR_KATEGORIE_WEGTUN · LIFE_CALENDAR_KATEGORIEN_ORDNEN · LIFE_CALENDAR_REGEL_SPEICHERN · LIFE_CALENDAR_REGEL_LOESCHEN · LIFE_CALENDAR_ABLEITUNG_SPEICHERN · LIFE_CALENDAR_ABLEITUNG_LOESCHEN · LIFE_CALENDAR_UEBERSTEUERUNG · LIFE_CALENDAR_VORLAGEN · LIFE_CALENDAR_VORLAGE_UEBERNEHMEN · LIFE_CALENDAR_VORLAGE_ABLEHNEN · LIFE_CALENDAR_FREMDKALENDER · LIFE_CALENDAR_FREMDKALENDER_SCHALTER.
Jeder davon fragt zuerst mit to_regclass, ob es die Tabellen gibt. migration84.sql ist inzwischen gelaufen (gemessen am 23.09.2026: life.calendar_categories trägt für ein eingerichtetes Konto fünf Zeilen — „Allgemein" als Vorgabe, dazu Geburtstage, Prüfungen, Ereignisse, Fälliges). Die Probe bleibt trotzdem stehen: Sie ist die Antwort für eine Datenbank, in der die Wanderung noch aussteht. Der Leseweg antwortet dann mit eingerichtet: false, die Schreibwege mit feature_not_available — „das gibt es hier noch nicht" und nicht „du hast keine". Der Unterschied ist der Befund B6; die Schirme zeigen in diesem Zustand einen Satz statt eines Formulars.
Das Vorlagenangebot ist eine Liste in einer Fläche (seit 10.10.2026, ES-261009-listen-flaechen-statt): Je Vorlage eine Zeile mit Namen und Beschreibung links und „Nehmen“ rechts, getrennt von Haarlinien. Vorher standen die Vorlagen als Kachelraster in einem Kasten mit Akzentrahmen — Karte in Karte. Seit ES-261010-restliche-kartenraster (ebenfalls 10.10.2026) sind die drei „Nehmen“ Nebenknöpfe: Drei gefüllte Hauptknöpfe untereinander hätten keinen Hauptknopf mehr gezeigt, und keine Vorlage ist die empfohlene.
Die Kästen liegen auf Papier (seit 10.10.2026, ES-261010-glastoene-liegenden): Vorlagenangebot, Verbindungen, Abos, Ausgabe, Kategorien, Regeln, Einzelheiten und die Felder im Stunden- und Monatsblatt sind Papier mit Haarlinie statt des halbdurchsichtigen Glastons. Zeigen und Gewähltes nehmen den ruhigen Ton ueberfahren, gewählte Termine und die Terminchips im Monatsblatt Karton, der gewählte Tag im Monatsraster den Schein der Anwendungsfarbe zu seinem Akzentrand. Glas trägt im Kalender nur noch die klebende Leiste beim Verlegen.
Die Vorlagen sind eine Instanzeinstellung, kein Datenmodell: kalender.vorlagen in personal.preference_defaults, eingebaute Vorgabe in shared/src/config/preferenceKeys.ts. Ob schon gefragt wurde, steht als Zeitstempel unter kalender.vorlage.gefragt in der Nutzerschicht — nicht im localStorage, sonst hieße „kommt nicht wieder" in Wahrheit „kommt auf jedem Gerät einmal wieder". Die Obergrenze der eigenen Zielkalender liegt unter kalender.zielkalender.hoechstens (Vorgabe 8, nur Instanz).
Mit welchem Konto, steht nicht im Rückruf. Wer im Browser auf „Mit Google verbinden" drückt, landet in verbindungenController.ts, und der schreibt (user_id, refresh_token, scopes, anbieter) — die Kontospalte bleibt leer, und auf beiden Schirmen stand danach „verbunden seit …" ohne Adresse daneben. Google danach zu fragen gehört auch nicht dorthin: Der Rückruf ist eine Weiterleitung, auf die der Browser gerade wartet, und ein Fehlschlag beim Dienst würde eine geglückte Verbindung zu einer gescheiterten machen.
Nachgetragen wird deshalb daneben — in calendar/server/kalender.ts, traegeKontoNach(). Steht ein Merkmal da und fehlt die Adresse, holt Denotato sie aus /calendars/primary (die Kennung des Hauptkalenders ist die Mailadresse, und calendar reicht dafür; userinfo.email verlangte eine eigene Zustimmung) und schreibt sie in beide Kontospalten. Das geschieht seit dem 24.09.2026 an drei Stellen (F71). Zuerst gleich nach dem Rückruf: loeseZustimmungEin stößt den Nachtrag über den Anschluss kalender.kontoNachtrag an, ohne auf ihn zu warten — die Weiterleitung wird nicht aufgehalten, und ein Fehlschlag ist eine Zeile im Protokoll, keine gescheiterte Verbindung. Dahinter stehen die beiden älteren Stellen als Rückfall, für den Fall, dass Google die Adresse beim Verbinden nicht herausgab: beim Holen des Kalenderstands — also genau auf dem Schirm, auf dem der Rückweg endet — und vor jedem Abgleich, der ohnehin mit Google spricht. Höchstens einmal je Verbindung, höchstens vier Sekunden lang, und wenn Google die Adresse nicht herausgibt, bleibt die Verbindung unberührt stehen. Im Nur-Lesen-Modus einer Impersonation unterbleibt der Nachtrag, weil der Kalenderstand schreibt: false trägt.
Die Adresse steht seit dem 24.09.2026 schon in der Antwort, die sie nachträgt (B17, Durchsicht). Der Zustand je Anbieter wurde vor dem Nachtrag gelesen und trug deshalb kein Konto; die Verbindungszeile zeigte die eben geholte Adresse erst beim nächsten Laden. Nach einem geglückten Nachtrag liest kalenderStand die Lage neu — einmal je Konto, nach dem Verbinden. Für den Nachweis nimmt kalenderStand dieselbe Naht wie traegeKontoNach (frage), damit verify:kalenderanbieter nicht bei Google anruft.
Was der Stundenplan fragt, kommt aus calendar/server/woche.ts — der Anschluss ANSCHLUESSE.kalender?.woche(…). Er liest life.events und sonst nichts, weil das die einzige Tabelle mit einer Uhrzeit ist, und gibt je Tag eine Zeile: nur der erste Tag trägt den Beginn, nur der letzte das Ende. Ein ganztägiger Eintrag trägt an keinem Tag eine Zeit (seit 22.09.2026): Seine zwölf Uhr in life.events ist eine Schreibweise — Mitternacht wäre eine Zone weiter der Vortag — und keine Auskunft.
Angelegt wird über LIFE_EVENT_SAVE (/api/life/events/save), also über denselben Endpunkt wie ein Ereignis unter /life. Der Kalender hat keinen eigenen Terminspeicher: life.events ist die einzige Tabelle in Denotato, in der ein Termin eine Uhrzeit hat — Prüfungen, Fristen und Geburtstage sind Tagesdaten. Angelegt wird mit active: true, weil der Sammler nur aktive Zeilen liest; ein Termin ohne dieses Feld wäre angelegt und unsichtbar.
Abonnements über /api/life/calendar/abos, /abos/neu, /abos/holen, /abos/pause, /abos/kuendigen und /abos/datei (eine hochgeladene .ics, legeAboAusDateiAn; das Feld im Schirm seit dem 24.09.2026, BE40); gelesen wird in sync/icsAbo.ts, geparst in @shared/handlers/life/ics.ts, nachgeführt von denotato-abos.timer alle dreißig Minuten. Die Termine landen in life.events mit feed_id und feed_uid — aber nur zur Ablage: Sie liegen dort, damit der nächste Abgleich weiß, was er beim letzten Mal geschrieben hat, nicht damit ein Schirm sie zeigt. Seit dem 22.09.2026 nimmt jede Stelle, die life.events liest, eine Zeile mit feed_id aus (Riss 7, zuletzt F49): Von dort aus steht ein Abo-Termin in keinem Briefing, keiner Übersicht, keiner Woche und keiner Ereignisliste — Denotato fasst keinen Termin an, den es nicht selbst geschrieben hat, und Anzeige ist Anfassen.
Gezeigt wird ein Abo-Termin seit dem 24.09.2026 aus dem Spiegel (N216, BE41). Derselbe Lauf schreibt die Datei ein zweites Mal ab, nach life.external_calendars (origin = 'ics', feed_id des Abos) und life.external_events — mit aufgeklappten Serien, von 40 Tagen zurück bis 400 Tage voraus, über spiegelzeilen aus sync/caldavSpiegel.ts wie bei iCloud; ein verschobenes Vorkommen (RECURRENCE-ID) ersetzt das reguläre. Eine Regel, die Denotato nicht lesen kann, bleibt bei ihrem ersten Termin (Punkt 122). Den Schalter „In Denotato spiegeln" setzt der Lauf nur, wenn er die Spiegelzeile anlegt; danach gehört er dem Menschen. Gelesen wird der Spiegel in gespiegelteTermine (database/controllers/spiegeltermine.ts) für origin icloud und ics — von Woche, Vorschau und Briefing, nie von sammleTermine und nie von der Ausgabe. Die Aboliste (abos.ts, ZEILEN_MIT_KATEGORIE) zählt aus dem Spiegel, sobald er einmal gelesen hat, und nimmt Name und Farbe der Kategorie von der Spiegelzeile. Nachgewiesen in verify:abos (Abschnitte „Und mit ihnen" und „Eine Reihe aus einem Abo, aufgeklappt").
Die Freigabe einer Kategorie (seit 23.09.2026, N148) über LIFE_CALENDAR_KATEGORIE_FREIGEBEN mit {id, freigeben} — gespeichert in life.calendar_categories.write_released_at (Wanderung 94; NULL heißt „angekündigt, nicht geschrieben"). Die Kategorienantwort trägt je Kategorie freigegebenAm und den abgeleiteten schreibstand (schreibt · angekuendigt · aus) und im Ganzen freigabesperre. Zurückgesetzt wird die Freigabe im Schreibweg der Kategorie (kategorien.ts, nimmFreigabeZurueck), nicht im Schirm — und seit dem 24.09.2026 (N225, BE55) nur noch dort: beim ersten Einschalten von „Nach draußen schreiben" und bei einem neuen Zielkalender, samt der Kategorien, die in ihn sammeln. Regeln und Ableitungen lassen sie stehen; was sie in eine freigegebene Kategorie lenken, schreibt der nächste Abgleich ohne neue Freigabe. Bis dahin nahm jede neue, geänderte, ausgeschaltete oder gelöschte Regel und jede aktive Ableitung sie weg (N149, nimmFreigabeWegenRegel, gelöscht). Nachweis l) in verify:kalenderanbieter. Gelesen wird sie im Abgleich (calendarCollector.ts, ladeKategorienlage), einmal je Lauf, und tolerant: Fehlt die Spalte, gilt jede Kategorie als freigegeben.
Der Strom nach draußen über LIFE_CALENDAR_ICS (der Stand für den Schirm), LIFE_CALENDAR_ICS_ERNEUERN, LIFE_CALENDAR_ICS_ZURUECKZIEHEN und LIFE_CALENDAR_ICS_SCHALTER. Derselbe Weg LIFE_CALENDAR_ICS trägt mit einem Token dahinter den Kalender selbst — als GET, ohne Sitzung und außerhalb der AES-Strecke, weil ein Kalenderprogramm keine hat. Die Adresse steht in life.calendar_exports (Migration 59), gebaut wird in calendar/server/ausgabe.ts, geschrieben in shared/icsSchreiben.ts, nachgewiesen von npm run verify:kalenderausgabe. Zu oft geholt gibt es 429 mit Retry-After und leerem Rumpf; die Eimer liegen im Speicher des Dienstes und nicht in der Datenbank, denn ein Zähler, der eine Abfrage kostet, kostet genau das, was er sparen soll — ein gebremster Abruf erhöht deshalb auch abrufe nicht (gemessen).
Was ein Abonnement hereingebracht hat, bleibt drinnen: Die Termine gehen nirgends mit hinaus — weder über den eigenen .ics-Strom (ausgabe.ts) noch über den Abgleich mit Google und iCloud (calendarCollector.ts) (Riss 7). Gezeigt werden sie seit dem 24.09.2026 sichtbar, aber schreibgeschützt aus einem eigenen Ort, life.external_events, statt über einen Filter auf life.events — so, wie es hier bis dahin als späterer Vorgang stand (N216). Liest Denotato denselben Kalender zusätzlich aus iCloud, steht er zweimal da, denn zwei Spiegel werden nie gegeneinander verglichen (Punkt 113); dann schaltet man einen der beiden unter „Fremde Kalender" aus.
Wegtun lässt sich ein Abo-Termin nicht (seit 23.09.2026, N169, F54): Er gehört dem Quellkalender, und der Papierkorb fasst ihn nicht an. Liegt trotzdem einer dort, holt ihn der nächste Abgleich zurück — als „geändert", mit derselben Kennung. Die Auswahl der bekannten Zeilen schließt weggetane deshalb ein: Der eindeutige Index auf (feed_id, feed_uid) gilt auch für sie, und eine Auswahl ohne sie liefe beim Anlegen ins ON CONFLICT DO NOTHING. Loswerden lässt sich ein solcher Termin nur im Quellkalender oder mit dem ganzen Abonnement.
Gespiegelt, aber nicht doppelt (BE43, AP4, seit 23.09.2026). Was aus einem eingeschalteten iCloud-Kalender kommt — und seit dem 24.09.2026 aus einem .ics-Abo (N216) —, prüft eine Stelle, spiegelOhneDubletten in calendar/server/kalender.ts, für alle Ansichten: die Vorschau (kommende im Bericht, das Blatt, die Zahl in heute), die Woche (stundenplan_kalendertermine, Kollisionen im Raster) und das Briefing (über den Anschluss kalender.spiegel).
Ort und Sport in der Woche und im Spiegel (BE56, N228, seit 24.09.2026). kalender.woche und kalender.spiegel tragen je Termin ort, das Feld „Ort“ (leer wird null). An einem Termin in der Kategorie, auf die die aktive Stundenplanregel art = sport zeigt, steht zusätzlich sport: true — gesucht wird sie mit sportkategorie in @shared/handlers/life/kategoriezuordnung.ts, der ranghöchsten solchen Regel; eine Regel ohne Filter oder mit „gesetzt“ zählt nicht. Es gibt kein eigenes Merkmal an der Kategorie und keinen Namen, der zählt: Wer die Kategorie umbenennt, bricht nichts, und ohne die Regel ist kein Termin Sport. Gemessen in verify:stundenplan, Abschnitt „Gespiegelter Sport“.
Verglichen wird mit dem, was die Ansicht selbst zeigt (seit der Prüfung vom 23.09.2026). Ein Spiegel fällt nur, weil derselbe Termin daneben steht; fällt er gegen etwas, das die Ansicht gar nicht zeigt, verschwindet der Termin ganz. Vorschau und Woche vergleichen deshalb mit Denotatos Terminen und mit allen Vorkommen des Stundenplans — die Übersicht auch, obwohl sie ihn nicht zählt (G1): Ein Spiegel, der eine Vorlesung ist, ist der Stundenplan. Das Briefing zeigt keine Ereignisse aus life.events und den Stundenplan eines Tages: morgens und mittags den von heute, abends seit dem 24.09.2026 den von morgen (BE53). Es vergleicht nur mit seinen festen Punkten aus personal.calendar_events und mit den Vorlesungen, die sein Block „Stundenplan" nennt, an deren Tag (briefingabgleich, @shared/handlers/briefing/briefingplan.ts). Bis zum 23.09.2026 verlor das Abend-Briefing die Vorlesungen von morgen aus einem Uni-Export, und ein Termin, den Denotato auch als Ereignis führt, stand dort an keiner Stelle; vom 23. bis zum 24.09.2026 standen sie abends nur in der Schreibweise des Exports da.
Die Regel steht in @shared/handlers/life/spiegeldubletten.ts:
- Die Zeit bleibt streng. Gleicher Tag und gleiche Minute des Beginns, immer; das Ende gleich oder auf einer Seite leer. Nur wenn die Titel wörtlich gleich sind, darf das Ende abweichen (ein Fristenexport schreibt gern eine feste Stunde).
- Der Titel passt, wenn die Kernwörter der einen Seite alle auf der anderen stehen — gleich oder als Abkürzung mit Punkt ab drei Buchstaben („Stat." zu „Statistische"; „Training" kürzt „Trainingslehre" nicht ab) — und nichts widerspricht. Zusätze in Klammern zählen nicht zum Kern.
- Abschnittsweise. Ein Titel zerfällt an Doppelpunkt, Mittelpunkt, Gedankenstrich, Schrägstrich, senkrechtem Strich, Semikolon und Komma in Abschnitte. Ein Abschnitt der anderen Seite, in dem ein Kernwort trifft, darf kein Kernwort tragen, das auf dieser Seite fehlt; ein Abschnitt ganz ohne Treffer ist ein Zusatz („Hörsaal 1"). „Statik" passt deshalb nicht zu „Stat. Methoden": In dem Abschnitt, in dem „Stat." es träfe, fehlt „Methoden".
- Was widerspricht. Die Art (Vorlesung/VL, Übung, Tutorium, Seminar, Praktikum, auch als Endung: „Zentralübung" ist eine Übung), wenn beide Seiten eine nennen und keine gemeinsame haben. Die Kennzeichen („I", „II", „Gr. 2", „Gruppe B") in ihrer Reihenfolge: Ist keine Folge der Anfang der anderen, sind es zwei Termine — „Physik I – Übung Gr. 2" ist nicht „Physik II – Übung Gr. 1". Der Anlass, erkannt am Wortteil: Prüfung und Klausur („Zwischenklausur", „Modulprüfung", „Midterm"), Ausfall und Änderung („fällt aus", „keine Vorlesung", „verschoben", „Raumänderung", „storniert", „vorlesungsfrei"), Sprechstunde, Lernen, Abgabe. Stehen auf beiden Seiten nicht dieselben Anlasswörter, ist es nicht derselbe Termin.
- Das Exportsignal. Ein Kalender, dessen Termine mit Uhrzeit mindestens viermal und zu mindestens drei Fünfteln auf die Minute genau (Beginn und Ende) auf Vorkommen des Stundenplans fallen, gilt als Export. Gemessen wird eine Woche zurück und vier voraus, gerechnet ab heute in der Zone des Kontos — für jede Ansicht dasselbe Fenster; bis zur Prüfung vom 23.09.2026 hing es an der Spanne der Ansicht, und derselbe Kalender war in der Woche ein Export und in der Vorschau über sechzig Tage keiner. Im Export genügt die genaue Zeit, wenn der Titel dort an mindestens zwei Tagen so auf den Stundenplan fällt (die Abschrift einer Serie) und nicht widerspricht — ein Kurscode ohne gemeinsames Wort fällt. Ein einzelner Eintrag zur Minute eines Stundenplaneintrags („Physio" und „Kinderbetreuung" zur Minute eines Trainings, „Dies academicus" zur Minute einer Vorlesung) bleibt: Das Signal urteilt je Kalender, und ein geteilter Sportkalender besteht es auch, ohne ein Export zu sein. Kein fest eingetragenes UID-Präfix: Das wäre die Gewohnheit eines Werkzeugs.
- Nie gegeneinander ausgeblendet werden zwei eigene Termine (ein Ereignis neben einer Vorlesung) und zwei Spiegel aus verschiedenen Kalendern (Punkte 111 und 113).
Nachgewiesen im Glied kalenderanbieter (Abschnitt „Am Stichtag steht jede Vorlesung genau einmal": ein Ausfall und ein einzelner fremder Termin zur Minute einer Vorlesung, ein Blockkurs hinter dem Fenster, das Briefing morgens und ohne Stundenplan — mit Gegenprobe), in verify:briefing (ein Tag nur mit Vorlesungen ist nicht leer; abends fällt die Exportkopie einer Vorlesung von morgen weg, ohne Stundenplan und mit dem Tag von heute bleibt sie) und in spiegeldubletten.test.ts.
Die Eule fasst die Woche zusammen (KI20, 27.09.2026). In der schwebenden Eule steht „Die Woche in einem Satz“ als Knopf. Er schickt nur die Kennung des Angebots an BEGLEITER_ANGEBOT; was das Modell liest, holt der Kalender selbst (calendar/server/angebote.ts): die Termine von heute bis in sechs Tagen in der Zone des Kontos, dieselben, die die Woche zeigt (wochentermine — eigene, Stundenplan, eingeschaltete fremde Kalender, ohne Dubletten), höchstens 60, je mit Tag, Uhrzeit, Titel und Kategorie. Ort, Kalendername und Farbe gehen nicht mit. Ein Klick zählt als freie Frage; was dahinter steht, sagt docs/seiten/begleiter.md, Abschnitt „Die Angebote der Eule“.
Als Baustein im Wiki (WI-261008-bausteine-artikel)
Stumm und mit festen Beispieldaten; Form und Wortlaut stehen in wiki.md unter „Bausteine im Artikel“. Ein Baustein: das Fach „Termin anlegen“ (calendar.event-form, Block). Das Absenden hält die Hülle an, bevor es den Weg erreicht.
Was fehlt
Es gibt keine Kalenderansicht— den Monat gibt es seit dem 17.09.2026,die Woche und den Tagseit dem 21.09.2026 (S-calendar), und mit ihnenden Weg zu den gezählten Terminen: Woche und Tag zählen nicht, dort steht alles da. Das Blatt zeigt dieselbe Vorschau wie die Liste: sechzig Tage ab heute, und es sagt es auch — ein Zeitraum ganz außerhalb der Spanne trägt eine Zeile darunter, statt einfach leer auszusehen. Was weiterhin fehlt, ist die Vergangenheit: rückwärts rechnet die Vorschau nicht, also ist jedes Blättern nach hinten ein leeres Blatt mit einer Erklärung.Man kann keinen Termin anlegen.— behoben am 21.09.2026 (S-calendar): Titel, Tag, Beginn/Ende und Ort im Anlegefach. Was bleibt: Personen und Art gibt es dort nicht (das ist/life), und ein angelegter Termin lässt sich auf diesem Schirm weder ändern noch löschen — siehe Punkt 27.Nur Google.— ICS-Abos gibt es seit dem 19.09.2026 (BE11): eine Adresse eintragen, und Denotato liest sie alle halbe Stunde. CalDAV schreibt seit dem 21.09.2026 auch aus dem Zeitgeber (BE10, F10).Was fehlt, ist das Lesen aus iCloud zurück, eine hochgeladene.ics-Datei ohne Adresse dahinter, und wiederkehrende Termine.— alle drei gebaut: das Lesen aus iCloud am 23.09.2026 (BE43), die Datei am 24.09.2026 (BE40), und am 24.09.2026 (BE41, N216) klappt der Spiegel die Serien eines Abos auf wie die aus iCloud — eine wöchentliche Vorlesung steht vierzehnmal da, nicht einmal. Inlife.eventswird eine Regel weiter nur gezählt, doch von dort zeigt keine Ansicht einen Abo-Termin. Mit BE13 (dem Wochenraster des Stundenplans) hatte das nie zu tun.- Gelesenes landet nirgends. (
„Denotato … liest nichts zurück"war zu pauschal:googleCalendar.tshat eine Lese-Seite,kommende(), und der Abgleichlauf ruft sie auf. Sie druckt aber nur auf die Konsole. Richtig bleibt der zweite Halbsatz: ein Termin, den man im Telefon einträgt, kommt nie in Denotatos Daten an.) Keine Kalenderansicht fürs Tagebuch— falsch, am 17.09.2026 nachgesehen:LifeMenuzeichnet im Abschnitt „Tagebuch" einMonatsrastermit Tagesauswahl und Einträgezahlen, und der Baustein nennt in seinem Kopf dieselbe Quelle („Christians Wunsch vom 11.09.2026"). Gebaut, nur nie abgehakt.Keine Konfliktanzeige.— behoben, in zwei Schritten. Am 22.09.2026 kam das Raster: Überlappende Termine stehen nebeneinander und tragen einen Warnrand samt dem Wort „doppelt" (calendar/shared/stundenraster.ts,tagesbloecke); Berühren zählt richtig nicht als Kollision. Am 23.09.2026 kam die zweite Hälfte (G1):kalendervorschaureicht die Stundenplanserien heraus und entfaltet sie zu einzelnen Vorkommen, sodass Vorlesung und Termin im selben Raster liegen und sich gegenseitig anwarnen. Was bleibt: Nur was eine Uhrzeit hat, kann kollidieren — Prüfungen, Fristen und Geburtstage sind in Denotato Tagesdaten und stehen über dem Raster. Siehe Punkt 50.- Kein Reisezeit-Puffer zwischen Orten.
'Europe/Berlin'steht fest im Google-Aufruf— behoben am 17.09.2026. Ein neu angelegter Kalender bekommt die Zone auszeit.zone, über alle vier Schichten aufgelöst (wirksamerWert(userId, …)— derselbe Weg wie im Schirm, nur ohne Sitzung, weil der Abgleich aus einem Zeitgeber kommt). Was bleibt: sie wirkt nur beim Anlegen. Wer die Zone später umstellt, ändert damit nicht die Zone eines Kalenders, den Google inzwischen führt — das wäre ein Eingriff in etwas, das jemand benutzt.- Kein Verlauf des Abgleichs. Was zuletzt geschrieben wurde, sagt niemand — nur wann und, seit dem 17.09.2026, ob er scheiterte und warum (
life.calendar_accounts.last_error, angezeigt als „Letzter Fehler: …"). - Keine Terminvorlage. „Vorlesung, dienstags, 90 Minuten" gibt es nicht.
Kein Wochenplan — und der Weg ist einseitig.— behoben am 23.09.2026 (G1). Seit dem 21.09.2026 (A23) lief der Anschluss nur in die andere Richtung: Der Stundenplan fragt überANSCHLUESSE.kalender?.woche(...)die Termine einer Spanne ab, zeichnet sie blass in sein Raster und warnt beim Anlegen. Jetzt geht es auch hierher — nicht über einen zweiten Anschluss, sondern übersammleTerminemitstundenplan: true, denn der Sammler liegt im Kern (backend/src/database/controllers/calendarCollector.ts) und nicht im Bereichstundenplan; ein Querimport zwischen zwei abschaltbaren Bereichen findet damit nicht statt (verify:archgrün). Was bleibt: Werstudyentzogen bekommt, sieht auch keinen Stundenplan mehr — der Sammler liest die Tabellen dann leer, er prüft das Merkmal nicht selbst. Siehe Punkt 67.Der Verbindungsknopf steht noch nicht hier— gebaut am 18.09.2026 (W08, V5). „Mit Google verbinden" steht jetzt im Abschnitt Verbindung, und der Rückweg wird hier gelesen:?verbunden=1und?fehler=<wort>werden zu einem Satz und anschließend aus der Adresszeile entfernt. Was bleibt: Das Trennen steht weiterhin nur unter Einstellungen → Zugangsdaten — der seltenere und folgenschwerere Griff bleibt an einer Stelle.- Der Knopf antwortet mit 501, solange die Rückleitungsadresse fehlt.
https://denotato.com/api/verbindungen/callbackmuss in der Google Cloud Console eingetragen sein; das ist Christians Konto und liegt als C31 bei ihm. Bis dahin führt der Knopf zu einer ehrlichen Fehlermeldung statt zu Google — sichtbar wird das erst auf diesem Schirm, weil hier niemand die Einstellungen offen hat. - Der Schirm zeigt einen Anbieter, obwohl zwei laufen. iCloud über CalDAV ist gebaut (BE10),
life.calendar_accountsträgt seit Migration 61 den Schlüssel(user_id, anbieter), und seit dem 21.09.2026 gleicht auch der Zeitgeber beide Anbieter ab (F10) — je Anbieter ein eigener Zustand, und ein gescheiterter Google-Lauf färbt nur die Google-Zeile. Was hier fehlt, ist die Ansicht: Der Zustandsbalken liest die Zeileanbieter = 'google'und sonst keine. Wer einen Apple-Zugang hinterlegt, sieht ihn arbeiten, aber nicht auf diesem Schirm. - Keine Verbindung zu Moodle-Fristen.
Ein Abonnement steht in keiner Verbindungsliste— behoben am 21.09.2026 (A24). Jedes Abo erscheint jetzt zusätzlich unter Einstellungen → Zugangsdaten in derselben Liste wie die Google-Verbindung, mit demselben Zustandssatz, undverbindungen_listenennt es mit. Der Ort hier bleibt, wo er ist — eingetragen, gelesen und gekündigt wird ein Abonnement weiterhin nur auf diesem Schirm; die andere Liste zeigt und verweist. Was bleibt: Die Zahl der Termine und „Jetzt lesen" gibt es dort nicht, und ein Konto, das nur die Einstellungen kennt, findet den Weg zum Eintragen nur über den Verweis.Ein Abonnement lässt sich nicht pausieren.— behoben am 21.09.2026 (BE11). Die Spalteaktivgab es seit Migration 45 und der Zeitgeber las sie; jetzt gibt es den Schalter dazu, an jeder Zeile, ohne Rückfrage. Ein pausiertes Abonnement sagt es in eigener Zeile und behält seine Termine — das ist der ganze Unterschied zum Kündigen. Was bleibt: Der gemeinsame Zustandssatz (A24) kennt nur verbunden · läuft ab · nicht eingerichtet, also sagt die Liste unter Einstellungen → Zugangsdaten weiterhin „verbunden seit …", auch wenn das Abonnement ruht. Eine vierte Lage dort anzulegen berührt drei Arten und gehört zu A22, nicht hierher.- DNS-Rebinding ist nicht abgedeckt. Die Adresse eines Abonnements wird vor dem Abruf aufgelöst und geprüft; ein Name, der beim Prüfen nach draußen zeigt und beim Abrufen nach drinnen, käme durch. Dagegen hilft nur, selbst zu verbinden statt
fetchzu benutzen. - Der Name eines Abonnements ist nicht änderbar. Er wird beim Eintragen gesetzt;
X-WR-CALNAMEaus dem Kalender wird gelesen, aber nicht angeboten. - Der Stundenplan fehlt im Strom nach draußen.
sammleTermine(calendar/…/calendarCollector.ts) liestlife.people,study.exams,life.events,game.tasksundstudy.exercise_attempts— die wiederkehrende Woche aus dem Bereichstundenplansteht in keiner davon. Damit fehlt gerade das, was man im Telefon am ehesten sehen will. Es hängt an derselben Frage wie Punkt 3: eine Wiederholungsregel muss aufgeklappt oder als Regel geschrieben werden (BE13). Der Strom kennt keine Erinnerungen.— behoben am 22.09.2026 (S-calendar): Jeder Termin im Strom trägt jetzt einen Alarmteil, und die Minutenzahl kommt aus „Erinnerung (Minuten vorher)". Der Nebensatz „gilt nur für Google" war falsch — die Einstellung wurde gespeichert, angezeigt und von niemandem gelesen:sync/googleCalendar.tsschreibt beim Anlegen eines Terminsreminders: { useDefault: true }und schaut die Zahl nie an. Sie war also überall tot, nicht nur hier. Seit dem 22.09.2026 wirkt sie an genau einer Stelle, dem Strom nach draußen. Was bleibt: die Google-Seite (Punkt 35), ein „aus" (Punkt 36) und der Ort, an dem der Schalter steht (Punkt 39).- Der Erzeugungszeitpunkt wandert bei jedem Abruf. Jeder Termin bekommt den Zeitstempel des Abrufs, weil der Sammler keinen Änderungszeitpunkt herausreicht. Streng gelesen sieht damit jeder Abruf nach „alles geändert" aus; kein bekanntes Programm stört sich daran, aber richtig ist es nicht.
- Eine Adresse je Konto, nicht je Art. Wer nur seine Prüfungen an einen geteilten Kalender geben will und seine Termine nicht, kann es nicht — die Schalter gelten für die eine Adresse.
- Die Adresse lässt sich nicht pausieren. Es gibt nur erneuern (andere Adresse) und zurückziehen (keine Adresse). „Für zwei Wochen still" heißt heute: zurückziehen und danach jedes Gerät neu einrichten.
Der öffentliche Weg ist ungezähmt.— behoben am 22.09.2026 (S-calendar). Zwei gleitende Eimer stehen jetzt davor: sechzig Abrufe je Kennung und hundertzwanzig je Adresse, beide in einem Fenster von einer Stunde. Gezählt wird beim Betreten und vor jeder Abfrage, sonst wäre es keine Rate, sondern eine Grenze für Gleichzeitigkeit.@fastify/rate-limitist weiterhin nicht eingebaut — die Rechnung darunter ist fünfzehn Zeilen (calendar/shared/abrufbremse.ts, zehn Zusicherungen), und eine Abhängigkeit braucht einen Satz (Grundsatz 67). Gemessen: der einundsechzigste Abruf einer Kennung ist 429 mitRetry-After: 3592, der hundertteinundzwanzigste einer Adresse ebenfalls, beide mit leerem Rumpf; von127.0.0.1bremst nichts (65 Abrufe, alle durch).Kein Ein-Klick-Abonnieren.— zur Hälfte behoben am 22.09.2026 (S-calendar): Unter der Adresse steht „Im Kalenderprogramm abonnieren", einwebcal://-Verweis, den iPhone, macOS, Thunderbird und Outlook direkt an ihren Kalender geben. Der Bildcode für die Übergabe aufs Telefon fehlt weiter — er ist eigentlich der wichtigere Weg, weil der Schirm am Rechner steht und der Kalender im Telefon; er steht jetzt als Punkt 37 für sich.- Ein Termin lässt sich hier nicht löschen, und ändern nur ein eigener, einzelner. Anlegen geht seit dem 21.09.2026, Titel, Tag und Uhrzeit eines eigenen Einzeltermins ändert seit dem 11.10.2026 der Aufklapper (F-261011-termin-aufklapper). Eine Serie, ein ganztägiger eigener Termin und alles aus anderen Quellen führen weiter zu ihrer Quelle (
/life,/study, …). Ein Termin, den man anlegen, aber nicht zurücknehmen kann, ist auch ein halbes Versprechen. - Das Anlegefach kennt keine Personen, keine Art und keine Beschreibung. Vier Felder — Titel, Tag, Zeit, Ort. Wer „Kaffee mit Toni" als Ereignis mit Toni will, legt den Termin hier an und verknüpft ihn danach in
/life. Das ist bewusst so (die Zeit steht im Mittelpunkt), aber es heißt: zwei Schirme für eine Sache. - Das Anlegen hängt am Endpunkt eines fremden Bereichs. Gerufen wird
LIFE_EVENT_SAVE, weillife.eventsdie einzige Tabelle mit einer Uhrzeit ist und ein eigener Terminspeicher dieselben Daten ein zweites Mal hielte. Sauber wäre ein Anschluss (ANSCHLUESSE.leben?.…) — so, wie der Stundenplan den Kalender fragt. Solange es ihn nicht gibt, verschwindet mit dem abgeschalteten Bereichlifeauch der Knopf, und zwar ohne dass dieser Schirm es merkt: Er bekäme einen 404 und zeigte ihn als Fehler. Die Woche hat keine Stundenspalte.— behoben am 22.09.2026.calendar/client/Stundenraster.tsxzeichnet die Woche und den Tag als Raster mit Stundenleiste; die Rechnung steht rein incalendar/shared/stundenraster.tsmit siebzehn Zusicherungen. Der alte Wortlaut:Die Woche hatte keine Stundenspalte. Sieben Felder untereinander sind eine Liste je Tag, kein Zeitraster: Ein Termin um 8 Uhr und einer um 20 Uhr stehen gleich weit oben, und die Lücke dazwischen sieht aus wie keine. Wer wissen will, ob der Nachmittag frei ist, sieht es nicht.
Kein Termin zeigt seine Uhrzeit.— behoben am 22.09.2026 (S-calendar): Im Blatt und in der Liste steht die Uhrzeit vor dem Titel — im Monat der Beginn, in Woche und Tag die Spanne —, und ganztägige Einträge stehen vor den Uhrzeiten desselben Tages. Der gemeinsame Sammler bringt weiterhin alles auf ganze Tage; umgangen wird er mit einer zweiten Abfrage (server/ereigniszeiten.ts), nicht mit einer Änderung an ihm. Was bleibt: Nurlife.eventshat überhaupt Uhrzeiten, und davon nur die Zeilen ohne Wiederholungsregel —ein wiederkehrender Termin aus einem Abonnement steht weiter ohne Zeit da (Punkt 3,BE13)(seit dem 24.09.2026 kommt er aus dem Spiegel, jedes Vorkommen mit seiner Zeit; BE41, N216). Und die Woche stellt sie nebeneinander, nicht auf eine Stundenspalte (Punkt 30).Wiederkehrende Termine lassen sich nicht anlegen.— behoben am 16.10.2026 (BE-261011-wiederkehrende-termine): Das Anlegefach trägt eine Wiederholung samt Wochentagen und letztem Tag (oben unter „Einen Termin anlegen“). Der alte Wortlaut: „Jeden Dienstag" gibt es hier so wenig wie eine Vorlage (Punkt 10).Und das Lesen solcher Regeln fehlt ebenfalls (Punkt 3,BE13).Gelesen und aufgeklappt werden sie seit BE43 (iCloud) und BE41 (.ics-Abos) im Spiegel (Punkt 3).Der Rückruf selbst schreibt die Kontoadresse weiterhin nicht.— behoben am 24.09.2026 (F71):loeseZustimmungEinstößt den Nachtrag nach dem Ablegen des Merkmals selbst an, ohne darauf zu warten (Anschlusskalender.kontoNachtrag, oben unter „Mit welchem Konto"). Die Adresse steht in der Datenbank, bevor irgendein Schirm den Kalenderstand holt. Der Satz über iCloud stimmte nicht: Die CalDAV-Zeile bekommt nie eine Adresse — kein Code schreibt sie —, braucht aber auch keinen Nachtrag, weil Denotato die Apple-ID aus dem Zugang kennt. Ob sie angezeigt wird, liegt als C47 bei Christian. Der alte Wortlaut:Der Rückruf selbst schrieb die Kontoadresse nicht. Seit dem 21.09.2026 (F15) trägt Denotato sie nach, sobald der Kalenderstand geholt oder abgeglichen wird — die Lücke ist damit für den Nutzer geschlossen, aber es bleibt ein Nachtrag und kein Mitschreiben. Wer nach dem Verbinden zuerst irgendwo anders hingeht, sieht unter Einstellungen → Zugangsdaten bis zum ersten Aufruf von
/calendarweiter „verbunden seit …" ohne Adresse. Dasselbe gilt für iCloud: Die CalDAV-Zeile bekommt ihre Adresse beim Speichern des Zugangs und hat keinen Nachtrag. Beides steht seit dem 23.09.2026 als eigener Vorgang F71; F15 ist erledigt (N163).Das Blatt merkt sich die Ansicht nicht.— behoben am 22.09.2026:denotato.kalender.ansichtimlocalStorage(calendar/client/merker.ts), Geräteschicht, jeder Zugriff eingepackt. Der alte Wortlaut:Das Blatt merkte sich die Ansicht nicht. Wer lieber in der Woche arbeitet, bekommt beim nächsten Aufruf wieder den Monat. Die Wahl gehört in die Einstellungsschichten neben
wochenstart, nicht in den Zustand einer Zeichnung.- Die Erinnerung erreicht Google immer noch nicht. Seit dem 22.09.2026 wirkt „Erinnerung (Minuten vorher)" im Strom nach draußen — in Google nicht:
sync/googleCalendar.tsschreibt weiterhinreminders: { useDefault: true }, also Googles eigene Vorgabe. Wer dort „90" einträgt und sich auf den Google-Kalender verlässt, bekommt nicht, was der Schirm verspricht. Zwei Wecker aus einer Zahl zu machen ist die richtige Antwort; sie gehört in den Abgleich und nicht hierher. - Die Erinnerung kennt kein „aus". Null Minuten heißen „im Augenblick des Termins", nicht „gar nicht". Sobald eine Zeile in
life.calendar_settingssteht, bekommt jeder Termin im Strom einen Wecker. Wer ihn loswerden will, muss die Einstellungen nie gespeichert haben — und das kann man nicht rückgängig machen. Ein leeres Feld statt einer Null wäre der Weg, aber das Feld ist heute eine Zahl mit Vorgabe. - Kein Bildcode für die Übergabe aufs Telefon. Der
webcal://-Weg hilft dem, der den Schirm auf dem Gerät offen hat, auf dem der Kalender liegt. Der übliche Fall ist der andere: Schirm am Rechner, Kalender im Telefon. Dafür bräuchte es einen Bildcode, und der bräuchte ein Paket — eine Abhängigkeit mit einem Satz (Grundsatz 67), also eine Entscheidung und kein Nebenbei. Der Stundenplan hält Ganztagstermine für Mittagstermine.— behoben am 22.09.2026 (S-calendar).wochentermineliest jetztall_daymit, und ein ganztägiger Eintrag kommt an keinem seiner Tage mit einer Uhrzeit heraus:beginn: nullheißt imWochenterminganztägig und nicht unbekannt, und alles auf der anderen Seite — Raster, Formular, Lernvorschläge — lässt eine solche Zeile stehen, ohne sie zu zeichnen und ohne sie kollidieren zu lassen. Gefehlt hat nur die Spalte in der Abfrage; docs/seiten/stundenplan.md beschrieb längst das Richtige. Am Stundenplan selbst ändert sich keine Zeile. Gemessen an vier Zeilen inlife.events: „Zahnarzt" 09:30–10:15 behält seine Zeit, „Geburtstag Toni", die dreitägige „Tagung" und der „Urlaubstag" (ganztägig mit Ende am selben Tag, der Fall, der bis dahin warnte) kommen ohne heraus.- Die Erinnerung steht am falschen Ort. Sie sitzt im Abschnitt Verbindung zwischen den Google-Einstellungen, wirkt aber im Abschnitt Nach draußen — zwei Bildschirmhöhen weiter unten. Der Hinweistext darunter sagt es seit dem 22.09.2026 in einem Satz, aber ein Satz ist die Entschuldigung für eine Anordnung, nicht ihre Berichtigung. Umziehen hieße, die Zahl zweimal zu zeigen oder die Einstellungen aufzuteilen; beides will vorher entschieden sein.
- Die Uhrzeit ist nirgends änderbar, wo sie jetzt steht. Im Blatt liest man seit dem 22.09.2026 „14:00", und der nächste Griff wäre, sie dort anzufassen — ein Ziehen, ein Klick, ein Feld. Es gibt nichts davon; der Klick führt zur Quelle (Punkt 27). Eine sichtbare Zeit lädt stärker zum Ändern ein als ein Titel allein, also ist diese Lücke seit heute auffälliger als vorher.
- Die Zahlen der Bremse stehen im Quelltext. Sechzig, hundertzwanzig und eine Stunde sind Konstanten in
calendar/server/ausgabe.ts. Nach A15 gehört eine Zahl, die man je Betrieb anders wollen könnte, in die Instanzschicht (@shared/config/instanzwerte) — ein Server mit drei Nutzern will etwas anderes als einer mit dreihundert, und heute heißt „anders wollen" einen Neubau. Der Vorschlag steht im Bericht zu S-calendar; die Datei ist geteilt, also fasst sie kein einzelner Trieb an. - Die Eimer überleben keinen Neustart — und keinen zweiten Prozess. Sie liegen im Speicher des Dienstes, wie die Bremse an der Anmeldetür. Wer Denotato neu startet, hebt jede Sperre auf; liefen zwei Prozesse hinter einem Verteiler, hätte jeder seinen eigenen Eimer und die Grenze wäre in Wahrheit die doppelte. Für einen Dienst auf einem Rechner ist das richtig — es kostet keine Abfrage, und genau die soll die Bremse sparen —, für zwei wäre es falsch, und nichts sagt es dann.
- Niemand erfährt, dass gebremst wurde. Es gibt keinen Zähler, keine Zeile im Protokoll und nichts auf dem Schirm. Wer eine Adresse verteilt hat und sie versehentlich alle fünf Sekunden abfragen lässt, sieht nur einen Kalender, der nicht mehr aktualisiert — und wer sie errät, tut es unbeobachtet. Eine Spalte neben
abrufewäre eine Antwort, aber ein Zähler in der Datenbank kostet die Abfrage, die die Bremse gerade vermeidet; das will entschieden werden. - Ein
Retry-Aftervon fast einer Stunde ist eine harte Antwort. Gemessen kommt beim einundsechzigsten Abruf3592heraus, weil alle sechzig Klopfer eben erst gefallen sind. Für ein Kalenderprogramm ist das richtig; für einen Menschen, der beim Einrichten dreimal falsch tippt und dann wartet, ist es lang. Ein zweiter, engerer Eimer für den ersten Ansturm (wie an der Anmeldetür) wäre die mildere Form, ist aber eine zweite Zahl mehr — siehe Punkt 41. Die Farbe hängt an der Art, nicht an einer Kategorie.— behoben am 23.09.2026 (G1).TerminzeileträgtkategorieId,kalenderStandfüllt sie aus dem, was der Sammler gerechnet hat (ordneEin), und der Schirm färbt und filtert danach. Ohne Regel gilt die Vorgabekategorie — gemessen für ein eingerichtetes Konto: 111 Stundenplanvorkommen in der grauen „Allgemein", weil keine Regel mitsource = 'stundenplan'existiert. Das ist sichtbar und richtig: Eine Kategorie anzulegen ist ein Handgriff, ein unsichtbarer Termin ist ein Fehler. Der Rückfall auf die festen Arten bleibt für ein Konto ohne Zeilen inlife.calendar_categories, und die Legende sagt es in einem Satz.Dreizehn der vierzehn neuen Endpunkte ruft die Oberfläche nicht auf.— behoben am 22.09.2026 (Welle D). Alle vierzehn werden gerufen,verify:archist grün. Der Befund im Wortlaut, weil er die Reihenfolge erklärt: Gebaut war zunächst nurLIFE_CALENDAR_KATEGORIEN(lesend). Die zwölf schreibenden Wege —…KATEGORIE_SPEICHERN,…KATEGORIE_WEGTUN,…KATEGORIEN_ORDNEN,…REGEL_SPEICHERN,…REGEL_LOESCHEN,…ABLEITUNG_SPEICHERN,…ABLEITUNG_LOESCHEN,…UEBERSTEUERUNG,…VORLAGE_UEBERNEHMEN,…VORLAGE_ABLEHNEN,…FREMDKALENDER_SCHALTER— brauchen die zwanzig Fehlercodes aus SCHEMA §10.2, und die gibt es nicht:grep -c CALENDAR_CATEGORYübershared/handlers/translation/messages.ts,shared/languages/de.jsonundbackend/src/config/messageCodes.tsergibt dreimal 0 (gemessen 22.09.2026).LIFE_CALENDAR_VORLAGENundLIFE_CALENDAR_FREMDKALENDERsind lesend, hängen aber an Tabellen bzw. an einem Einstellungsschlüssel, die es ebenfalls nicht gibt.verify:archmeldete dafür zu Recht dreizehn Verstöße. Die Codes stehen seit Welle D Schritt 1, die Wege und Schirme seit Schritt 2.Es gibt kein Vorlagenangebot.— behoben am 22.09.2026. Der Kasten steht über der Woche und geht genau einmal auf; drei Vorlagen, ablehnbar, und beides setzt den Zeitstempel. Der Befund im Wortlaut: SCHEMA §8.2 verlangt beim ersten Öffnen ein ablehnbares Angebot („Studium", „Arbeit", „Nur Privates"), dessen „nicht wieder" als Zeitstempel inpersonal.preferencesunterkalender.vorlage.gefragtliegt — ausdrücklich nicht imlocalStorage. Den Schlüssel gibt es nicht: gesucht inshared/src/config/preferenceKeys.ts, kein Treffer fürkalender.. Ohne ihn wäre jedes Angebot entweder gerätegebunden (also falsch) oder unablehnbar.Die Farbauswahl ist eine Anzeige, keine Bedienung.— behoben am 22.09.2026.Farbwahl.tsxbietet die zehn Töne, ein freies Hex-Feld und je Szene einen Probestreifen in echten Farben statt einer Kontrastzahl. Geprüft wird weiter incalendar/client/farbe.ts(vierzehn Zusicherungen); der Ausdruck^#[0-9a-f]{6}$liegt jetzt inshared/kategorien.ts, weil der Server dieselbe Prüfung braucht.FARBAUSWAHList eine Nachtpalette.— behoben am 29.09.2026 (E11, N345): Die Tagszene dunkelt jede Kategorienfarbe beim Malen je Ton bis zur Drei-zu-eins ab, höchstens auf die Hälfte; gespeichert bleibt der gewählte Wert (Guide §3.6). Die Szenenwarnung der Legende und die Tagprobe der Farbwahl rechnen mit der abgedunkelten Fassung und melden sich am Tag nur noch, wenn selbst sie nicht trägt. Der Befund von damals: Gemessen am 22.09.2026 gegenNEUTRALE.tag.grund(#f7eee9): Blau 2,47 · Türkis 2,18 · Limette 1,56 · Laub 1,78 · Amber 1,40 · Orange 2,05 · Magenta 2,48 · Rot 2,72 · Grau 2,93 — neun von zehn unter 3:1; nur Violett (#a631ff, 4,08) trägt. In der Nacht trägt jede (4,10 bis 11,97). Der Schirm sagt es in einem Satz je Szene statt in einer Warnung je Kategorie; die Tagszene braucht eine eigene Tonleiter, und das ist eine Entscheidung. Heute trägt jeder der zehn Töne am Tag (farbe.test.ts).Der Stundenplan steht nicht im Kalender.— behoben am 23.09.2026 (G1).kalendervorschaunimmt seit heute einenVorschauzusatz; der Kalenderschirm setzt darinstundenplan: true, der Anschlussvorschau(Dashboard) nicht — vier Argumente, und die Antwort bleibt dort zeichengleich. WeilsammleStundenplantermineeine Serie liefert (ein Anfangstag, eine Wiederholungsregel und die Ausfalltage) undkommendeTerminedaraus genau einen Tag rechnen kann, entfaltetentfalteWochenseriensie vorher zu einzelnen Vorkommen. Gemessen für ein eingerichtetes Konto, Woche vom 09.11.2026: vorher 0 Stundenplantermine, nachher 17; über 60 Tage 124 Zeilen statt 13, davon 111 aus dem Stundenplan, keine Dublette. Der Abgleich sieht davon nichts:gleicheAnbieterAbbekommt weiterhinstundenplan: false, undnpm run kalender -- --dry-runmeldet unverändert22 unveraendert.Die Zahlen der Verbindungszeile gelten für alle Anbieter zusammen.— behoben am 23.09.2026 (F60, Bens Befund K1).kalenderStandliefertanbieterje Anbieter (eingerichtet, letzter Abgleich, letzte Störung, Termine) ausanbieterlage(sync/kalenderdienste.ts), und jede Verbindungszeile zeigt ihre eigenen Zahlen. Dieselbe Stelle speistheuteund die Verbindungsliste; ein nicht gewählter Anbieter neben einem gewählten meldet keine Störung mehr.- „Verbunden" misst weiterhin Anwesenheit, nicht Gültigkeit (B2b).
verbindungenController.ts:313-328liestlife.calendar_accountsund setztverbunden = k !== undefined; ein zurückgezogenes Merkmal steht dort genauso. Der Schirm stellt deshalb seit dem 22.09.2026 den letzten Fehler des Dienstes gleichrangig daneben („Der Dienst hat zuletzt abgewiesen: …") und färbt die Zeile — er behauptet also nichts Falsches mehr, aber er weiß es immer noch nicht. Eine echte Antwort gäbe erst eine Probe beim Dienst (zugang_pruefen, WP3). - Die Kollisionsanzeige kennt keine Reisezeit. Zwei Termine, die sich nicht überlappen, aber an zwei Orten dreißig Minuten auseinanderliegen, fallen nicht auf. SCHEMA §4.3 sieht dafür
life.calendar_derivations(„Anfahrt") vor; die Tabelle gibt es nicht, und der Schirm rechnet nichts dergleichen. - Keine Druck- oder PDF-Ausgabe der Woche. Weder ein
@media print-Block noch ein Knopf; gesucht incalendar/client/**— kein Treffer fürprint. Das Raster ist absolut positioniert und bräuchte dafür eine eigene Fassung. - Der Schirm weiß nicht, welche Übersteuerungen schon gesetzt sind.
…/kategoriengibt Kategorien, Regeln und Ableitungen zurück, aber keinelife.calendar_overrides. In den Einzelheiten eines Termins stehen deshalb drei Knöpfe, die sagen, was sie tun, und nicht, was gilt: „Ausblenden" sieht gleich aus, ob der Termin schon ausgeblendet ist oder nicht. Gesucht incalendar/server/kategorien.ts(standVon) — die Abfrage gibt es nicht, weil eine Übersteuerungsliste ohne die Termine, auf die sie zeigt, eine Liste von Kennungen wäre. Richtig wäre diekategorieIdan der Terminzeile (Punkt 45). - Eine Übersteuerung gilt nur für einen Tag, nie für die Serie.
life.calendar_overrideskenntoccurrence_on IS NULLfür „die ganze Serie" und hat dafür einen eigenen Teilindex; der Schirm schickt immer ein Datum. Für eine wöchentliche Vorlesung, die dauerhaft in eine andere Kategorie gehört, müsste man vierzehnmal klicken — oder eine Regel anlegen, was meist das Richtige ist. Ein zweiter Knopf „für alle" wäre die kleinste Antwort. - Der Filterwert einer Stundenplanregel ist freier Text.
study.veranstaltungen.artistvarchar(32)und kein Enum; die Menge gehört dem Konto. Denotato bietet deshalb kein Auswahlfeld, sondern ein Eingabefeld und einen Satz daneben. Die belegten Werte ständen in der Datenbank — sie zu holen hieße, auscalendarinstundenplanzu greifen, und das ist ein verbotener Querimport. Der legale Weg ist ein Anschluss (ANSCHLUESSE.stundenplan?.…, B-3). - Die Zielkalendergrenze steht nicht im Satz, der sie meldet.
calendar_target_limit_errorsagt „mehr legt Denotato nicht an" ohne die Zahl, weil der Übersetzungsweg (meldungstext.ts) keine Platzhalter füllt — der*-Platzhalter wird nur inlogHelper.ts:41-42ersetzt. Die Zahl steht im Antwortkörper (grenzen.eigeneZielkalender) und im Zähler unter der Kategorienliste, aber nicht im Fehlersatz. Das ist B-18. - Regeln und Ableitungen ändern sofort, ohne Probelauf. Für den Abgleich gibt es „Erst durchrechnen"; für eine Regel gibt es nichts Vergleichbares — man sieht erst nach dem nächsten Abgleich, welche Termine sie wirklich trifft. Eine Vorschau („diese Regel griffe bei 23 der nächsten 60 Tage") bräuchte
ordneZuaus SCHEMA §5.4, und die Datei gibt es nicht. - Kategorien lassen sich nicht ziehen, nur mit Pfeilen schieben. Bei zwölf Kategorien sind das im schlimmsten Fall elf Klicks für eine Zeile.
ordneKategoriennimmt die ganze Reihenfolge entgegen, trägt also ein Ziehen problemlos; gesucht incalendar/client/Kategorienverwaltung.tsx— es gibt keinendragstart. Am Telefon wäre Ziehen ohnehin die schlechtere Bedienung, also ist es eine Ergänzung und kein Ersatz. - Der Vorlagenkasten lässt sich nicht zurückholen. „Nein danke" setzt
kalender.vorlage.gefragt, und danach gibt es in der Oberfläche keinen Weg zurück zum Angebot — nur das Zurücksetzen der eigenen Einstellungen (/settings) räumt den Schlüssel wieder weg. Der Schlüssel steht in der Stufeeinfach, genau dafür; ein Knopf „Vorlagen ansehen" neben der Kategorienliste fehlt trotzdem. life.external_calendarsfüllt niemand. Die Liste der fremden Kalender wird gelesen und lässt sich schalten — geschrieben wird sie von keinem Abgleich:sync/googleCalendar.tsundsync/caldav.tslisten Kalender nur, um den eigenen Zielkalender zu finden (stelleKalenderBereit), und legen keine Zeile an. Bis das jemand baut, bleibt die Liste auch nach der Wanderung leer, und der Schirm sagt dann „verbunden, aber der Anbieter nennt keinen Kalender".- Eine Regel nimmt im Schirm genau einen Filterwert.
filter_valuesist eintext[], der Endpunkt nimmt bis zu 32 Werte — das Formular bietet ein Feld bzw. eine Auswahl und schickt höchstens einen. Für „Prüfungen, aber nur Klausur und mündlich" braucht man deshalb zwei Regeln auf derselben Kategorie. Das geht (zwei Regeln auf eine Kategorie ist nach SCHEMA §9 der Normalfall), ist aber ein Umweg, den ein Mehrfachfeld spart. Gesucht incalendar/client/Regelverwaltung.tsx— dort stehtfilterWerte: [wert]. Der Legendenfilter trifft nie, sobald es Kategorien gibt.— behoben am 23.09.2026 (G1), in zwei Schritten. Der Befund im Wortlaut, weil er die Bauart des Fehlers zeigt: Die Legende schriebkategorie.idin den Merker (Kategorienlegende.tsx), der Schirm suchte zu einem Termin die Kategorie überrueckfallId(termin.art), also überart:ereignis— und die Bestandskonten tragen UUIDs. Gemessen am 22.09.2026: Schnittmenge null, auch mit allen fünf Kategorien ausgeblendet wurde kein Termin gefiltert. Am 22.09.2026 fiel die eine Hälfte: Filter und Farbe fragen dieselbe Zuordnung (filterschluessel). Am 23.09.2026 die andere:kommendeinLIFE_CALENDARträgtkategorieIdundquelle(calendar/server/routen.ts,CalendarStatusSchema;calendar/server/kalender.ts,kalenderStand). Gemessen danach: fünf Legendenschlüssel, drei belegte Filterschlüssel, Schnittmenge drei. Gefärbt wird jetzt wirklich nach der Kategorie und nicht nur scheinbar richtig, weil Wanderung 84 dieselben Töne gesetzt hatte.- Die drei Ausgabeschalter waren bis zum 22.09.2026 wirkungslos. Der Haken schrieb
life.calendar_exports.with_*, den Strom entschied seit Wanderung 84life.calendar_categories.in_ics_feed— gemessen haben alle zwölf Konten Kategorien, der Rückfallpfad wird also von keinem mehr gegangen. Behoben:setzeAusgabeSchalterschreibt beide Seiten,liesAusgabezeigt den wirksamen Wert, undverify:kalenderausgabelegt dem Probekonto jetzt die drei Bestandskategorien an, statt den Rückfall zu messen (acht neue Zusicherungen). Was bleibt: Eine Kategorie ohnelegacy_kind— jede selbst angelegte — hat im Ausgabefach keinen Schalter; sie wird nur in der Kategorienverwaltung geschaltet. Drei feste Haken für eine Tabelle mit beliebig vielen Zeilen sind ein Rest, kein Endzustand. - Ein Konto mit leerer Kategorientabelle bekam die Erklärung der anderen Lage. Die Legende sagte „gibt es, sobald die Kategorientabelle in der Datenbank steht" — auch dann, wenn die Tabelle längst stand und nur die Zeilen fehlten. Am 22.09.2026 getrennt (
tabelleDaanKategorienlegende), und zugleich die Ursache beseitigt:provisionNewUserlegt jedem neuen Konto die eine Vorgabekategorie „Allgemein" an. Was bleibt: Für die zwölf Bestandskonten hat das Wanderung 84 getan; ein Konto, das zwischen Wanderung und diesem Tag entstanden ist, hat keine — nachgesehen wurde das nicht, weil es in dieser Datenbank kein solches gibt (life.calendar_categorieshat 24 Zeilen mit identischemcreated_at, alle aus der Wanderung). - Der Stundenplan hat im Rückfall keinen eigenen Ton. Ein Konto ohne Zeilen in
life.calendar_categoriesbekommt für seine Vorlesungen den Eintrag „Stundenplan" in der Legende — aber in Grau (TERMIN_UNBEKANNT), weilTERMINFARBENinfrontend/src/theme/terminarten.tsvier Arten kennt und der Stundenplan keineTerminartist. Die Datei gehört nicht zum Kalenderpaket; der Name steht deshalb inKalendermenue.tsxvon Hand daneben (RUECKFALLNAMEN), der Ton bleibt grau. Eine fünfte Zeile dort ist der ganze Fix — sie gehört in denselben Commit wie die Farbtabelle, nicht hierher. Abonnierte Fremdkalender stehen nicht in der eigenen Woche.— behoben, für iCloud-Kalender am 23.09.2026 (BE43), für.ics-Abonnements am 24.09.2026 (BE41, N216): Beide werden gespiegelt und stehen in Woche, Vorschau und Briefing; der Riegel unten bleibt, er gilt nur noch dem Schreiben. Was ein.ics-Abonnement nachlife.eventsschreibt, trägtfeed_id, undsammleTermineliest ausdrücklichfeed_id IS NULL(Riss 7, F24) — der Riegel, der verhindert, dass Denotato fremde Termine als eigene wieder hinausschreibt. Für die Anzeige wäre er nicht nötig, für das Schreiben ist er unverzichtbar; beides in einer Abfrage zu unterscheiden gehört in den Sammler und damit in den Kern. Heute ohne Wirkung: gemessen am 23.09.2026 hatlife.calendar_feeds0 Zeilen undlife.events WHERE feed_id IS NOT NULLebenfalls 0. Der Bedarf steht indocs/auftrag-kalender/SCHEMA.md.- Die Vorschau hat eine Decke von 400 Zeilen, und der Stundenplan füllt sie.
VORSCHAU_HOECHSTENSschneidet nach dem Sortieren ab — wer sechzig Tage weit rechnet und pro Woche zwanzig Vorlesungen hat, kommt gemessen auf 124 Zeilen und damit weit darunter. Bei einem vollen Plan über mehr als sechzig Tage wäre das Ende der Liste stillschweigend abgeschnitten, und das Raster zeigte einen leeren Dezember, ohne es zu sagen. Ein Fenster je Ansicht statt einer festen Decke wäre die richtige Form; heute reicht die Zahl. - Ein Stundenplantermin lässt sich aus dem Kalender nicht ändern. „Wohin man geht, um ihn zu bearbeiten" führt auf
/stundenplan, aber ohne Anker auf die Veranstaltung — der Schirm dort zeigt eine Woche und keine Zeile. Eine Übersteuerung (Kategorie, verborgen) geht dagegen direkt, weillife.calendar_overridesquelle,quelleTabelle,quelleIdundtagträgt und die Vorschauzeile alle vier liefert. „Pausiert" hat seit der Prüfer-Nachbesserung vom 23.09.2026 gar kein Zeichen mehr— behoben am 30.09.2026 (E12):Ruhtträgt das Zeichenpausein Blau, das Wort ist neutral. Der alte Befund: (Punkt 127) —gesperrtwar die falsche Bedeutung (Sperre statt gewollter Ruhe), und ein eigenespausegibt es in der Registry nicht. Gewünschter Name:pause— zwei parallele Striche, dieselbe Bedeutung wie das Symbol auf jedem Player, klar getrennt vongesperrt(verboten) undblockiert(kaputt, hängt fest). Bis dahin bleibt das Wort „Pausiert" selbst blau (theme.colors.status.info, BE11). Sobald es den Namen gibt, gehört er inRuht(calendar/client/Kalenderabos.tsx), das Blau wandert aufs Zeichen, und das Wort wird neutral — wie überall sonst nach N134. Eingetragen als Wunsch in E12.ueberfaelligträgt die Kategoriefarbe statt der Warnfarbe — außer im Blatt. Die Nachbesserung vom 23.09.2026 (Punkt 4 des Prüferberichts) hatzeichenfarbe()nur dort eingesetzt, wo der Befund sie fand: Monat, Woche (Agenda) —Monatsblatt.tsx. Incalendar/client/Termineinzelheiten.tsx:256steht weiterhin<Zeichen name={zeichen} groesse={14} farbe={kategorie.farbe} />ohne die Ausnahme — derselbe Fehler, nur eine Datei weiter, außerhalb dieser Runde.Die Oberfläche selbst wartet ohne Grenze.Erledigt am 24.09.2026 (A30, Schritt 4b). Schon seit B1 gibtnormalRequestjeder Anfrage 60 s (ANFRAGEFRIST_MS). Für den Abgleich wäre das zu kurz gewesen, weil der Server bis zu 90 s braucht, bevor er selbst abbricht (Punkt 74).syncCalendargibt deshalb eine eigene Frist mit,ABGLEICHFRIST_MS= 120 s, über der des Servers und unter den 300 s von nginx. So kommt der Satz des Servers auf den Schirm, statt dass der Knopf vorher mit „unbekannter Fehler" aufgibt.Eine Grenze für den ganzen Lauf fehlt.Erledigt am 24.09.2026 (A30, Schritt 3, N160). Ein Abgleich hat jetzt eine Gesamtfrist je Konto, über Google und CalDAV zusammen:KALENDER_LAUF_TIMEOUT_SECONDS, Vorgabe 90 s (sync/zeitgrenze.ts,Laufgrenze). Ist sie um, bricht die laufende Anfrage ab, jede weitere scheitert sofort, ein zweiter Anbieter beginnt nicht mehr. Der Lauf gilt als abgebrochen:last_errorsagt „Der Abgleich hat seine Gesamtfrist von 90 s ueberschritten und wurde abgebrochen (…).",last_sync_atbleibt stehen, und der Bericht bleibt leer, auch wenneigentum()den Fehler geschluckt hat (Punkt 77).- Ein gescheitertes Löschen drüben lässt die Verknüpfung trotzdem fallen.
calendarSync.ts(um Zeile 1160) wertet einen Löschfehler, in dessen Text404oderdeletedsteht, als Erfolg, und löscht die Zeile inlife.calendar_linksauch bei jedem anderen Fehler. Seit A30 trägt ein Zeitablauf keinen Pfad im Text, und die einzige Zahl darin, die Frist, bleibt unter 404, weilfristAus()höchstens 300 s zulässt; der erste Teil kann also nicht mehr falsch treffen, undverify:caldavgeht dafür jede zulässige Frist durch. Der zweite bleibt: Ein Termin, dessen Löschen an der Frist scheitert, bleibt draußen stehen, und Denotato weiß danach nichts mehr von ihm. - Der Nachweis sieht nur
sync/und zwei Dateien daneben.verify:caldavprüft, dass jederfetchunterbackend/src/sync(samt Unterordnern) und im Google-Rückruf und im Tausch von Hand eine Frist trägt. Einfetchan einen der drei Dienste in einer dritten Datei außerhalb vonsync/fiele nicht auf. Besser wäre eine Prüfung über alle Aufrufe an die Hosts ausshared/config/aussenverbindungen.ts. Zur Laufzeit geprüft sind CalDAV (gegen einen echten stillen Sockel) und Google (gegen einen nachgebautenfetch, weil die Adressen dort fest verdrahtet sind). Die Notion-Frist selbst (Vorgabe 30 s, Riegel) prüft kein Nachweis zur Laufzeit:verify:archhält Notion aus jedem Ausführbaren außerhalb vonbackend/src/sync/notionheraus, und ein eigener Nachweis dort braucht eine neue Zeile inpackage.json. - Verstummt ein Anbieter mitten im Lauf, meldet der Bericht fremde Termine statt einer Zeitüberschreitung. Vor jedem Ändern, Umziehen und Löschen liest der Abgleich die Marke des Termins draußen (
eigentum()incalendarSync.ts, um Zeile 297). Scheitert das Lesen, fängteigentum()jeden Fehler und antwortet „nicht unserer". Das ist für die Sicherheit richtig — gelöscht wird nichts —, aber die Meldung stimmt nicht: Schweigt der Server beim ersten Lesen einer Marke, landet jeder weitere Termin sofort am Riegel, und alle stehen im Bericht als „nicht angefasst: … traegt draussen keine Marke dieses Kontos", zählen als nicht angefasste fremde Termine mit dem Zeichenschild, und inlast_errorsteht dieser Satz statt „… hat nicht innerhalb von 20 s geantwortet". Der Fall setzt voraus, dass der Server am Anfang des Laufs noch antwortete — schweigt er von Anfang an, scheitert schonkalenderGibtEs()und der ganze Lauf endet mit dem richtigen Satz. Die Abhilfe liegt incalendarSync.ts:eigentum()bekommt einen dritten Ausgang, etwa{ unser: false, stoerung: string }, und die drei Schleifen schreiben dann „nicht angefasst: „X": <Fehlertext>" und zählen nicht ingeschuetzt. - Der Titel einer Zusammenfassung wird im Monatsfeld beschnitten, und die Grenze ist eng. H1 gibt ihm 64 Zeichen (
TITELBUDGET); ein Feld des Monatsrasters zeigt bei sieben Spalten etwa fünfzehn bis zwanzig. Beschnitten wird hinten —text-overflow: ellipsisauf einernowrap-Zeile, also bleibt der Anfang stehen und das Ende fällt weg;Fällig: Analysis-Ab…ist immer noch mehr als2 To-Dos fällig, aber die acht ZeichenFällig:gehen von den fünfzehn ab. H1 nennt die billigere Form selbst: bei einem Posten den Namen allein stehen lassen und die Zahl nur beim Überlauf führen — ein Handgriff anfaelligTitel, sobald jemand entscheidet. Der Zeigerhinweis trägt seit H2 die volle Liste, aber nur dort, wo es einen Zeiger gibt. - Eine Wiedervorlage führt auf
/tutor, ohne die Aufgabe zu zeigen.quelleIdist die Kennung eines Versuchs (study.exercise_attempts.id,calendarCollector.ts), der Tutorschirm listet Aufgaben (ExerciseRow.idausstudy.exercises). Ein?id=mit der Versuchskennung hübe nichts hervor. Abhilfe: entweder der Sammler trägt zusätzlichexercise_id(ein Feld anFaelligkeit, also eine Entscheidung und keine Spalte), oder der Tutorschirm nimmt eine Versuchskennung entgegen und löst sie selbst auf. Beistudy.examsging es einfacher, weil die Kennung dort die Prüfung selbst ist (NV15, 03.10.2026). - Der laufende Dienst ist älter als dieser Schirm, bis jemand ihn neu startet. Er läuft ohne
tsx watchdirekt aus dem Arbeitsbaum, kenntpostenalso noch nicht und liefert die Vorschauzeile ohne das Feld. Bis dahin zeigt das Einzelheitenfach seinen Rückfall — die Beschreibung mit ihren Zeilenumbrüchen und den Satz „Woraus dieser Tag besteht, kam nicht zerlegt an …" —, und der Zeigerhinweis im Monat nennt nur den Titel. Das ist gewollt und geprüft (Termineinzelheiten.test.tsx), aber es heißt auch: Wer den Schirm vor dem Neustart ansieht, sieht nicht, was hier steht. Der Dienst war dabei nicht der einzige Grund: Bis zum Abend des 23.09.2026 las auch der Schirm das Feld nicht, und ein neuer Dienst hätte denselben Rückfall gezeigt (Punkt 106). - Die Vorschau nennt ihre Grenze nur in der Antwort, nicht im Schirm. Seit dem 23.09.2026 (F60) trägt
kalenderStandein Feldvorschaumittage,bis,hoechstensundabgeschnitten, und die MCP-Beschreibung nennt die sechzig Tage. Das Blatt sagt die Spanne in einer Zeile, sobald man über sie hinaus blättert, aber es zeigt nicht, wenn die Decke von 400 Zeilen gegriffen hat. letzterFehleroben fasst zusammen und verliert dabei den Anbieter. Das Feld nennt die erste Störung in der Reihenfolge Google, iCloud — wer beide nutzt und beide scheitern, liest oben nur Googles. Je Anbieter steht es inanbieter; die Zeile „Zuletzt gemeldet" im Abgleichsfach liest noch das zusammengefasste Feld.- „Eingerichtet" heißt bei iCloud: ein Zugang liegt da. Ob Apple ihn noch annimmt, weiß erst der nächste Lauf; bis dahin steht „eingerichtet" neben einem Passwort, das Apple vielleicht schon zurückgezogen hat. Dasselbe wie Punkt 52 für Google.
Eine Serie mit Uhrzeit geht weiter ganztägig hinaus.— behoben mit BE37, festgehalten mit BE59 (24.09.2026). Eine Serie mit Zone geht als Wanduhrzeit mitTZIDhinaus, dieVTIMEZONEdavor auszonenblockin@shared, jedesEXDATEmit derselben Wanduhr.verify:caldavprüft eine Serie ab dem 01.12. — 09:00 mitTZID, kein Zeitpunkt in UTC, im Zonenblock der Übergang am 25.10. um 03:00 von +0200 auf +0100 — und als Gegenprobe eine ab dem 13.10., die vor und nach der Umstellung dieselbe Wanduhr trägt. Gemessen hat Ben am 24.09.2026 eine Vorlesung im Dezember in iCloud zur richtigen Ortszeit. Seit BE59 schickt auch die Anfrage MKCALENDAR die Zone als ganzesVCALENDARmitVTIMEZONEstatt als bloßen Namen (RFC 4791 §5.2.2); ob iCloud den Unterschied bemerkt, ist nicht gemessen.- Ein Ereignis ohne Ende steht draußen als Zeitpunkt. Ohne
ends_atschreibt der Abgleich nurDTSTART— eine Dauer zu erfinden wäre schlimmer. Apple zeigt so einen Termin als Strich ohne Länge; wer das nicht will, trägt in Denotato ein Ende ein. - Gespiegelt wird nur, solange der Schreibabgleich läuft. Der Spiegel hängt am iCloud-Lauf des Abgleichs (BE43): Wer den Abgleich ausschaltet, weil er nichts nach draußen schreiben will, liest auch nichts mehr herein. Beides sind zwei Wünsche, und der Schalter kennt nur einen.
- Eine Serie mit einer ungewöhnlichen Regel steht nur einmal da.
BYSETPOSund die Regelteile nach Wochennummer, Jahrestag oder Stunde liest der Aufklapper (@shared/handlers/life/wiederholung.ts) nicht; er zählt sie im Bericht (nichtAufgeklappt) und zeigt nur das erste Vorkommen. Im Schirm steht die Zahl nirgends. - Die Dublettenerkennung vergleicht nur Uhrzeit und Titel. Zwei Termine zur selben Minute mit passendem Namen sind für sie derselbe — auch wenn der eine in einem anderen Raum stattfindet. Umgekehrt bleibt eine Vorlesung, die der Export fünf Minuten anders führt, doppelt stehen. Ob ein Termin als Dublette ausgeblendet wurde, sieht man nirgends. (Seit dem 23.09.2026, AP4: Der Titelvergleich kennt Arten, Kennzeichen in ihrer Reihenfolge, Anlässe als Wortteil, Abkürzungen mit Punkt und Abschnitte, und in einem Exportkalender genügt für eine Serie die genaue Zeit — die Zeitregel ist dieselbe geblieben, der Raum zählt weiter nicht, und gezeigt wird das Ausblenden weiter nirgends.)
- Die Farbe eines gespiegelten Termins kommt im Blatt erst über eine Kategorie an. Der Kalender bringt seine eigene Farbe mit (
remote_color), und die Fremdkalenderliste zeigt sie; das Blatt färbt aber nach Kategorie, und ein Spiegel ohne Kategorie steht grau. „Eingelesen am" nennt den Tag in UTC.— behoben am 09.10.2026 (VA-261009-tagesangaben): Der Satz nimmt den Zeitgeber des Kontos und nennt den Tag in dessen Zone und Sprache, kurz nach Mitternacht also nicht mehr den Vortag.- Die Rechnung je Kategorie steht in der Antwort, nicht im Schirm. Seit dem 23.09.2026 (N148) trägt der Abgleichbericht
jeKategoriemit Stand, Ziel, Einträgen und Plan für jede Kategorie; der Schirm zeigt davon nur die Tabelle je Zielkalender und die Hinweise. Wer wissen will, warum „Übungen“ nichts schreibt, liest das MCP-Werkzeug oder den Zeitgeber. - Der Stundenplan geht erst nach einer neuen Freigabe hinaus (BE37). Geschrieben wird er als Serie mit
TZIDundVTIMEZONE; Ausfälle und verlegte Tage stehen alsEXDATEan der Serie, eine Verlegung als eigener Termin mit ihrem Raum (N157). Eine Freigabe vor dem 24.09.2026 deckt ihn nicht, und der Schirm sagt das nur als „nicht geschrieben“ in der Tabelle je Zielkalender — den Satz, dass neu freigegeben werden muss, tragenzurueckgestelltGrundund die Hinweise. Eine Stundenplanzeile ohne passende Kategorie geht nie hinaus; sie steht unter den zurückgehaltenen. - Eingefroren wird ein Kalender, nicht ein Termin. Die Merkzeile (
life.calendar_links) weiß nicht, welcher Kategorie ein Termin gehörte, nur, in welchem Kalender er liegt. Deshalb wartet in einem Kalender, in den eine angekündigte Kategorie mitschreibt, jede Löschung — auch die des freigegebenen Sammlers —, bis sie freigegeben oder ausgeschaltet ist. Und umgekehrt bleibt eine Lücke: Hat eine angekündigte Kategorie ihr Ziel gewechselt und liegt keiner ihrer noch gewollten Termine mehr im alten Kalender, wird dort ein Termin mit verschwundener Quelle weiter weggeräumt. Beides verschwände mit einer Kategoriespalte an der Merkzeile (eine Wanderung). - Die Zahlen je Kategorie zählen je Anbieter nicht getrennt. Die Antwort addiert die Planzahlen über Google und iCloud und nimmt die Einträge einmal; wer es je Anbieter braucht, liest das Protokoll des Zeitgebers (
npm run kalender -- --dry-run). - Die Freigabe hat keine Rückfrage. „Freigeben" schreibt beim nächsten Lauf in einen fremden Kalender, und der Knopf tut es auf einen Klick; der Satz daneben verlangt den Probelauf, der Schirm prüft aber nicht, ob einer gelaufen ist. Eine Freigabe, die erst nach einem Probelauf mit denselben Zahlen möglich ist, wäre die strenge Form — dafür müsste der Probelauf irgendwo stehen bleiben.
- Wer freigegeben hat, steht nirgends.
write_released_atist ein Zeitpunkt, kein Name; bei einem Konto mit zwei Menschen (Impersonation durch einen Verwalter) sagt die Kachel nicht, wer es war. Das Protokoll der Sitzung weiß es, die Kategorie nicht. - Der laufende Dienst kennt die Freigabe erst nach dem Neustart. Route, Rücksetzen und Kachel wirken ab dem nächsten Neustart von
denotato-api; bis dahin gibt es den Weg nicht (verify:endpointsist rot, bis er da ist). Der Zeitgeber dagegen liest die Sperre, sobald der Code im Arbeitsbaum steht. - „Im eigenen .ics-Strom" wirkt nur an vier Kategorien. Der Strom liefert nach Art aus (
ausgabe.ts,stromplan), und nur die Bestandskategorien mitlegacy_kindsagen etwas über eine Art. Der Haken steht an jeder Kategorie im Formular und tut an allen anderen nichts — ein Schalter, der nichts schaltet. Behoben wäre es, wenn der Strom die Zuordnung des Sammlers läse (je Termin seine Kategorie) statt der Art; das ist ein Umbau am Strom und steht aus. - Die Doppelweg-Warnung kennt nur iCloud. Sie fragt, ob der Strom und CalDAV dieselben Termine tragen; wer den Strom in Google abonniert und Google zugleich beschreiben lässt, bekommt keinen Satz, obwohl dasselbe passiert.
Eine Übersteuerung und die Schalter nehmen die Freigabe nicht weg.Erledigt am 24.09.2026 (N225, BE55): Auch eine Regel und eine Ableitung nehmen sie nicht mehr weg, damit behandeln Regeln, Übersteuerungen und die Schalter unter „Was geschrieben wird" die Freigabe gleich. Bis dahin sperrte seit N149 jede Regeländerung breit die Kategorien, in die dadurch Termine kommen konnten — auch solche, die am Ende nichts bekamen. Geblieben ist: Was eine Regel in eine freigegebene Kategorie lenkt, geht beim nächsten Lauf ohne Rückfrage hinaus; wer das vorher sehen will, nimmt „Erst durchrechnen".- Die Vorlage sieht bei iCloud keinen neuen Kalendernamen. Nach einem neuen Zielnamen behält CalDAV den Pfad (Riss 14), und der Kalender heißt draußen weiter wie vorher — „Draußen: angelegt“ stimmt also, der Name nicht. Bei Google zählt die Vorlage die Umzüge in den neuen Kalender mit.
- Eine verhindernde Regel kann nicht nach Art filtern. Welche Stundenplanarten ein freier Tag wegnimmt, sagt seit dem 23.09.2026 seine Art (C37, Christians Entscheidung N149): Ein Feiertag nimmt alles, ein vorlesungsfreier Tag nur die Lehre — das Letzte als feste Eigenschaft je Art im Code (
ENTFAELLT_AN_FREIEN_TAGEN), gerechnet inentfaelltAnFreiemTag(@shared/types/stundenplan.ts). „Am Feiertag auch den Sport verhindern" heißt damit: den Tag im Stundenplan als Feiertag eintragen, nicht eine Regel schreiben. Die Filterfelder einersuppress-Regel gehören weiter der auslösenden Quelle (freier_taghat keine), nicht der verhinderten; eine feinere Wahl — etwa „nur den Sport, nicht die Arbeit" — bräuchte einen Filter auf der verhinderten Quelle, und das wäre eine Vertragsänderung (SCHEMA §5.4). - Die Vorgaberegel „Freie Tage verhindert: Stundenplan" rechnet selbst nichts. Die freien Tage wirken auf den Stundenplan über seine Serie:
stundenplanserieträgt jeden freien Tag einer Lehrveranstaltung als Ausfalltag ein, seit C37 jeden Feiertag auch jeder anderen Veranstaltung — ob die Regel aktiv ist oder nicht. Der Sammler fragt die Regel für Zeilen des Stundenplans seit dem 23.09.2026 gar nicht mehr (Rohtermin.freieTageEingerechnet), weil er eine Serie nur an ihrem ersten Tag fragen konnte und dann die ganze nahm: Ein Zusatztermin am freien ersten Tag einer Vorlesung riss so das ganze Semester aus der Vorschau. Wer die Regel ausschaltet, bekommt die Vorlesungen am Feiertag deshalb nicht zurück. Ob der Schalter das künftig tun soll oder der Schirm die Regel für den Stundenplan als „fest" zeigt, ist eine Entscheidung; gebaut ist keines von beiden. Derselbe Fehler — eine Serie an ihrem ersten Tag gefragt — trifft weiter jede andere Serie, die eine verhindernde Regel ankreuzt: Ein Geburtstag ist eine jährliche Serie, die im laufenden Jahr beginnt; fällt er dieses Jahr auf einen freien Tag, fehlt die ganze Serie, bis das Jahr wechselt. Nicht angefasst, weil der Geburtstag dafür ein eigenes Ausfalldatum bräuchte. - Ein gespiegelter Termin ohne Kategorie steht in der Farbe eines Ereignisses, nicht in der seines Kalenders.
farbeVonfragt die geladene Kategorienliste und fällt dann auf die Art zurück. Seit dem 23.09.2026 trägt die Vorschauzeile die Fremdfarbe (farbebeikategorie: null, AP5), der Schirm nutzt sie nicht. Eine Zeile infarbeVon— aber eine sichtbare Änderung, die einen Blick braucht; nicht gebaut. - Die Farbe einer Übersteuerung wird nirgends gezeigt.
life.calendar_overrides.colorlässt sich speichern (kategorien.ts) und wird mitgeladen (Terminuebersteuerung.farbe), aber weder die Zuordnung nochfarbein den Antworten lesen sie. Ob eine Übersteuerung den Termin umfärben soll, ohne die Kategorie zu wechseln, ist nicht entschieden. Die Posten einer Zusammenfassung kamen nie am Schirm an.— behoben am 23.09.2026. Der Dienst schickte sie seit H1/H2,Terminzeilekannte das Feld, Einzelheitenfach und Monatsblatt zeigen es — aberzuTerminzeile(calendar/client/anfragen.ts) baut jede Zeile Feld für Feld neu und schriebpostennicht ab. Jeder zusammengefasste Tag fiel deshalb auf seine Beschreibung zurück, auch gegen einen neuen Dienst. Die Schirmtests reichten den Bausteinen die Posten von Hand und sahen die Lücke nicht. Jetzt liestzuPostendie Liste tolerant: Fehlt sie, bleibt sie weg; ein Eintrag, dessen Titel, Tabelle oder Kennung keine Zeichenkette ist, fällt heraus; ein leerer Titel bleibt, weil der Sammler ihn mitzählt.anfragen.test.tsprüft den Weg von der Antwort zur Zeile, samtkategorieundfarbe. Gegenproben:postennicht abgeschrieben undnullstatt Fehlen bei der Kategorie — drei von vier Prüfungen rot; eine leere Liste statt Fehlen — die vierte rot.- Ob die genannte Kategorie ruht, sagt die Zeile nicht. Ein Termin, der in eine Kategorie mit
aktiv: falsefällt, entsteht nicht: Der Sammler lässt ihn weg (ordneEin),kommendeführt ihn nicht, das Blatt zeigt ihn nicht. Die Woche des Stundenplans (stundenplan_kalendertermine) nennt ihn dagegen mit Name und Farbe der ruhenden Kategorie, weil er stattfindet; ein gespiegelter Termin steht in beiden. So steht es seit dem 23.09.2026 inkategorieangabe.tsund in beiden Werkzeugbeschreibungen, nachgewiesen inverify:kalenderanbieter(Teil m, Fall 7). Ob die Kategorie ruht, liest ein Modell heute auskalender_kategorien(aktiv). Ein Feldruhtan der Zeile kommt nicht: Christian hat am 24.09.2026 entschieden, dass die Werkzeugbeschreibungen genügen (N223, C50). Ein Termin eines fremden Kalenders trug die Kennung einer weggetanen Kategorie.— behoben am 23.09.2026.kategorieWegtunhängt nurlife.calendar_entriesauf die Erbkategorie um; die Zuordnung am fremden Kalender (life.external_calendars.category_id) bleibt stehen.spiegeltermine.tslas sie ungeprüft: Eine Zeile inkommendetrug danach die Kennung der weggetanen Kategorie, aberkategorie: nullund die Farbe des fremden Kalenders — drei Felder, die einander widersprachen —, und die Fremdkalenderliste nannte dieselbe tote Kennung. Beide lesen sie jetzt aus dem Join auf eine lebende Kategorie. Gegenprobe: beide wieder mitc.category_id— die zwei Prüfungen in Teil m, Fall 8, rot. Die Zuordnung in der Datenbank bleibt stehen; waskategorieWegtunmit ihr tun soll, gehört zu Punkt 110.Keine Übersteuerung ließ sich setzen.— behoben am 23.09.2026.uebersteuerungSetzenschrieb seit WP6 (22.09.2026)updated_by_idinlife.calendar_overrides, und die Tabelle hat diese Spalte nicht (Wanderung 84, nurcreated_by_id). „Umhängen nach …" und „Ausblenden" in den Einzelheiten eines Termins scheiterten deshalb mit „column … does not exist", der Schirm zeigte einen internen Fehler; „Wieder wie gerechnet" ging, weil die Löschanweisung die Spalte nicht nennt. Gefunden hat esverify:kalenderanbieter, der seitdem eine Übersteuerung anlegt und ändert (Teil m, Fall 9). Gegenprobe:updated_by_idzurück in die Änderungsanweisung — der Lauf bricht an der zweiten Übersteuerung ab. Im laufenden Dienst gilt der Fehler weiter, bis die Behebung inbetasteht und denotato-api danach neu startet;betaträgt ihn seit WP6 ebenso.Die Regeln und Übersteuerungen einer weggetanen Kategorie ruhen nicht.— behoben am 24.09.2026 (F87, Christians Entscheidung N223). Bis dahin ludladeKategorienlagealle Regeln und Übersteuerungen des Kontos, undordneZufragte nicht, ob ihre Kategorie noch lebt: Nach dem Wegtun von „Uni" fielen die Vorlesungen (über eine Regel) und ein übersteuerter Termin in keine Kategorie (gemessen am 23.09.2026 mit dem Prüfkonto von Teil m). Den Papierkorb, denkalender_kategorie_loeschenversprach, gab es nicht. Jetzt gilt:- Die Regeln ruhen.
ladeKategorienlageundstandVonlassen Regeln, Ableitungen und Übersteuerungen einer weggetanen Kategorie aus; ihre Termine fallen auf die übrigen Regeln oder die Vorgabe, wie ein Termin ohne Regel. Eine Übersteuerung verliert dabei nur ihre Kategorie — Farbe und „Ausblenden" gelten weiter. Die Einträge hängtkategorieWegtunan die Vorgabe;erbeAnist fort, gewählt wird nichts mehr. - Die Freigaben der übrigen bleiben (Ben am 24.09.2026, N225). Was jetzt in eine andere Kategorie fällt, schreibt der nächste Abgleich ohne neue Freigabe, wie bei einer Regel, die jemand anlegt oder löscht. Die Rückfrage sagt das vorher.
- Papierkorb, dreißig Tage. Die Kategorie ist eine Art im gemeinsamen Papierkorb (
kalenderkategorie, Einstellungen → Deine Daten); weggetan wird sie nur hier, weil das Wegtun die Einträge umhängt. Zurückgeholt gelten ihre Regeln und Ableitungen wieder; sie selbst bekommt ihre vor dem Wegtun bestehende Freigabe zurück (N263/F95), sofern ihr eigener Kalenderzugang beziehungsweise ihr Sammelziel noch besteht; sonst kommt sie angekündigt zurück. Im Papierkorb bleibt die Freigabe durch den Riegel unwirksam. Die Ziele ihrer Ableitungen behalten ihre Freigabe. Trägt eine lebende Kategorie denselben Namen, lehnt der Papierkorb das Zurückholen ab. Ebenso seit dem 24.09.2026 (F95), wenn das Konto schon 64 lebende Kategorien hat oder wenn sie in einen eigenen Zielkalender schreibt und die Grenze der eigenen Zielkalender erreicht ist — mit demselben Satz wie beim Anlegen. - Endgültig gelöscht gehen Regeln und Ableitungen mit, ebenso eine Übersteuerung, die nur die Kategorie sagte; eine mit eigener Farbe, Verschiebung, Notiz oder Ausblendung bleibt, ohne Kategorie. Hängt noch ein Eintrag an ihr oder sammelt eine andere Kategorie in sie, löscht der Papierkorb sie nicht: Einzeln sagt er es, Leeren und Frist lassen sie liegen. Einen Eintrag, den ein gleichzeitiger Abgleich noch an sie hängte, hängt der nächste echte Abgleich an die Vorgabe (F95); danach geht auch sie. Die Zuordnung eines fremden Kalenders (Punkt 108) bleibt so lange stehen und gilt nach dem Zurückholen wieder; beim endgültigen Löschen verliert der fremde Kalender nur die Zuordnung.
Wanderung 122 setzt den Riegel
calendar_category_trashed_unreleased(eine Kategorie im Papierkorb trägt keine Freigabe) und gibt allen weggetanen dreißig Tage ab der Wanderung; gesperrt wird dabei nichts (N225). Ohne sie bleibt alles wie vorher, und Rückfrage wie Werkzeug sagen es (ruhen: false). Nachgewiesen inverify:kalenderanbieter(Teil n) undverify:papierkorb(„Eine Kategorie tut selbst weg und wird festgehalten"). Gegenproben:ruhtfest auffalse— die zwei Prüfungen, wohin die Termine fallen, rot;nimmFreigabeWegenRegelzurück ins Wegtun — „Nachfolger" verliert die Freigabe, Teil n rot. F95 ist seit dem 25.09.2026 abgeschlossen. Gebaut ist: Das Zurückholen prüft die Höchstzahl der Kategorien und die der eigenen Zielkalender; ein Eintrag, den ein gleichzeitiger Abgleich noch an eine weggetane Kategorie hängt, zieht beim nächsten echten Abgleich an die Vorgabe; zeigt eine Sammlerin in eine weggetane Kategorie, nennt der Abgleich den Papierkorb als Grund; eine Kategorie, in die eine lebende andere sammelt, lässt sich nicht wegtun — der Satz der Abweisung nennt die Sammlerinnen (N263). Wanderung 148 merkt die vorherige Freigabe getrennt und der Papierkorbanschluss stellt sie nach erfolgreichem Zurückholen in derselben Transaktion wieder her, wenn das Schreibziel noch besteht; danach wird der Merker geleert (N263).- Die Regeln ruhen.
- Ein eigenes Ereignis neben der Vorlesung steht zweimal da. Die Dublettenprüfung vergleicht nur Spiegel mit Denotato, nie zwei eigene Termine miteinander (AP4, 23.09.2026). Ein Ereignis „Erste Vorlesung: Fach" zur Minute der Vorlesung „Fach (VL)" im Stundenplan bleibt deshalb neben ihr stehen — in
kommende, im Blatt und als Kollision im Raster. Gemessen am 23.09.2026 an einem echten Konto: am 13.10. genau dieser Fall, einmal. Denotato blendet es nicht aus: Christian hat am 24.09.2026 entschieden, dass ein eigenes Ereignis stehen bleibt (N223, C48). Wer es nicht mehr will, löscht es selbst. - Eine Frist aus einem Export und Denotatos Tageszusammenfassung erkennen sich nicht. Ein Export schreibt „Erledigen: Blatt 3" (mit Uhrzeit oder ganztägig), Denotato fasst dieselbe Frist als „Fällig: …" für den ganzen Tag zusammen. Andere Titel, oft eine andere Zeitform — die strenge Zeitregel lässt beide stehen.
- Zwei Spiegel derselben Sache aus zwei Kalendern stehen beide da. Verglichen wird Spiegel gegen Denotato, nicht Spiegel gegen Spiegel; wer denselben Termin in einem Uni- und einem Fristenkalender hat, sieht ihn zweimal, solange Denotato selbst keinen dazu führt. Seit dem 24.09.2026 (N216) gilt das auch für ein
.ics-Abo neben demselben Kalender aus iCloud; einen der beiden schaltet man unter „Fremde Kalender" aus. - Das Exportsignal braucht vier Treffer. Es urteilt über eine Woche zurück und vier voraus, gerechnet ab heute; am Rand des Semesters oder bei einem Kalender mit nur einer Vorlesung fällt ein Export unter die Schwelle, und dann gilt wieder nur der Titel. Umgekehrt urteilt es je Kalender, nicht je Termin. Seit der Prüfung vom 23.09.2026 fällt ohne Titeltreffer nur noch, was im Kalender als Serie auf den Stundenplan fällt (mindestens zwei Tage); ein einzelner privater Eintrag zur Minute einer Vorlesung bleibt stehen. Ein wiederkehrender fremder Eintrag in einem Exportkalender, jede Woche genau zur Minute einer Vorlesung und ohne widersprechendes Wort (eine „Lerngruppe" im Uni-Kalender, eingetragen mit Beginn und Ende der Vorlesung), fällt weiter mit — er ist von der Abschrift einer Serie nicht zu unterscheiden.
- Eine Vorlesung aus dem Export an einem freien Tag bleibt stehen. Hat Denotato den Tag frei (
study.freie_tage), gibt es dort kein Vorkommen des Stundenplans, gegen das der Spiegel fallen könnte — der Export weiß vom freien Tag nichts und zeigt die Vorlesung weiter. - Der laufende Dienst zeigt die neue Regel erst nach dem Neustart. Vorschau, Woche und Briefing lesen sie aus dem Code von
denotato-api; bis zum nächsten Neustart zeigenkommendeundstundenplan_kalenderterminedie alte, die bei keiner Vorlesung griff. Das gilt auch für die Nachbesserung aus der Prüfung vom 23.09.2026 (Anlässe, Reihenfolge der Kennzeichen, festes Fenster, Serienregel, Briefing). - Ein Titel, der nur den Wortstamm teilt, passt nicht mehr. „Mathe" steht nicht in „Mathematische Grundlagen", und „Programmierung" nicht in „Einführung in die Programmierung": Eine Abkürzung zählt nur mit Punkt, und ein Abschnitt, in dem ein Wort trifft, muss ganz gedeckt sein. Das ist der Preis dafür, dass „Training" nicht mehr zu „Trainingslehre (VL)" passt. Im Exportkalender fällt so ein Spiegel trotzdem, wenn er als Serie auf den Stundenplan fällt; außerhalb steht er doppelt da.
- Außerhalb des Semesters erkennt das Signal keinen Export. Das Fenster liegt fest um heute. In der vorlesungsfreien Zeit trifft ein Uni-Export dort keine Vorlesung, und wer schon die Wochen des nächsten Semesters ansieht, bekommt nur den Titelvergleich — ein Kurscode ohne gemeinsames Wort steht dann neben der Vorlesung. Ein Fenster um die Ansicht wäre genau der Fehler, den die Prüfung vom 23.09.2026 fand: zwei Ansichten, zwei Urteile über denselben Kalender.
- Die Spiegel werden meist zweimal gelesen. Einmal für die Spanne der Ansicht, einmal für das feste Fenster um heute; nur eine Ansicht, deren Spanne das Fenster ganz deckt, kommt mit einer Abfrage aus. Vorschau, Woche und Briefing brauchen heute alle zwei. Gemessen ist die Dauer nicht (B08).
Abends nennt das Briefing die Vorlesungen von morgen nur aus einem Export.— behoben am 24.09.2026 (BE53, Christians Entscheidung N223, C49). Bis dahin zeigte das Briefing abends keinen Stundenplan, und seit dem 23.09.2026 fielen die gespiegelten Vorlesungen von morgen dort nicht mehr weg. Wer keinen Uni-Kalender einlas, las am Abend nichts über die Vorlesungen des nächsten Tages. Jetzt nennt der Block „Stundenplan" abends die Vorlesungen von morgen, undbriefingabgleichbekommt sie mit dem Tag von morgen: Ihre Exportkopien fallen als Dubletten weg (verify:briefing).- Eine Kalenderdatei bleibt unter „Dateien" liegen (BE40, 24.09.2026). Der Schirm lädt sie hoch, bevor der Server sie liest. Lehnt er sie danach ab — kein
BEGIN:VCALENDAR—, oder wird das Abo später gekündigt, bleibt die Datei in der Ablage stehen; einen Weg, eine Datei wegzuräumen, hat die Oberfläche heute nicht. Die Grenze von 5 MB fängt der Schirm vorher ab, den Inhalt kann er nicht prüfen. Dazu: Eine neuere Fassung ersetzt die alte nicht, sie wird ein zweites Abo — deshalb sagt die Zeile, dass die alte gekündigt werden will. Sauber wäre „Neue Fassung" an der Zeile, das dieselbe Zeile über denselben Vergleich nachzieht; gebaut ist das nicht. - Eine Serie, die Denotato nicht aufklappen kann, zählt beim Abo niemand (BE41, 24.09.2026). Eine Regel, die der Leser nicht versteht, bleibt bei ihrem ersten Termin — beim Abo wie bei iCloud. Der iCloud-Spiegel nennt ihre Zahl im Abgleichbericht (
nichtAufgeklappt); der Abo-Lauf (spiegeleinsync/icsAbo.ts) verwirft sie, und die Aboliste sagt nichts. Die Zahl an der Abozeile wäre ein neues Datenfeld; nicht gebaut. - Am Telefon lässt sich ein Termin nicht ziehen (BW-261007-kalender). Das Ziehen hört auf Maus und Stift; ein Finger auf dem Blatt wischt und blättert. Beides auf derselben Fläche braucht ein langes Drücken als Unterscheidung — das gehört zu den Gesten (BW-261007-gesten).
- Ein Vorkommen einer Serie lässt sich nicht ziehen. Der Server kann es verlegen (
LIFE_EVENT_MOVE), der Schirm bietet es nicht an, weil dann zu fragen wäre, ob nur dieses oder alle folgenden wandern. - Der Vorschlag nennt seine neue Zeit nur in der Leiste. Der gestrichelte Block steht schon an der neuen Stelle, seine Zeile trägt aber bis zum Verlegen die alte Uhrzeit.
Ein Abo-Termin ist seit dem 22.09.2026 nirgends mehr sichtbar— behoben am 24.09.2026 (BE41, N216): Er steht aus dem Spiegel in Woche, Vorschau und Briefing, schreibgeschützt, wie unten als spätere Antwort benannt. Der alte Text: Er war nirgends sichtbar, auch nicht dort, wo Denotato ihn früher zeigte (Riss 7, F49). Das ist richtig, solange die einzige Alternative war, ihn versehentlich anzufassen — aber wer nachsehen will, was ein Abonnement eigentlich bringt, hat keinen Ort dafür mehr. Die spätere Antwort ist sichtbar, aber schreibgeschützt: ein eigener Ort (life.external_events) statt eines Filters auflife.events, damit ein Abo-Termin gezeigt werden kann, ohne dass ein Knopf danebensteht, der ihn ändert. Nicht gebaut, nur benannt.„Pausiert" trägt das Zeichengesperrt, obwohl ein pausiertes Abonnement keine Sperre ist.— behoben am 23.09.2026 (Prüfer- Befund): ein Schloss heißt eine Sperre, nicht eine gewollte Ruhe.Ruhtincalendar/client/Kalenderabos.tsxzeigt bis auf Weiteres gar kein Zeichen mehr, nur das Wort — und das bleibt blau (theme.colors.status.info), wie BE11 es festgelegt hat: ohne Zeichen wäre ein neutrales Wort vom Normalfall nicht mehr zu unterscheiden. Die Regel „das Wort bleibt neutral" (N134) gilt erst, wenn ein Zeichen die Farbe übernimmt. Der Wunsch nach einem eigenen Zeichen bleibt offen — Punkt 71.- „Vor Ort oder online" hat nirgends ein Zeichen, obwohl die Registry mit
ortundonlinegenau das Paar dafür vorsieht. Der einzige Ort, an dem die Werteirl/online(calendar/shared/regeln.ts,FILTERFELDER.ereignis) je einem Menschen angezeigt werden, istcalendar/client/Regelverwaltung.tsx— eine Datei außerhalb des Zuschnitts dieser Runde (N134, 23.09.2026). Selbst dort stehen die beiden Werte als reiner Text in den<option>-Beschriftungen eines nativen<select>-Feldes (um Zeile 525:{ value: wert, label: wert }) — ein<option>kann kein gezeichnetes Zeichen aufnehmen, das ist eine Grenze des HTML-Elements und keine des Zuschnitts. Ein Zeichen dafür gibt es erst, wenn dieses eine Feld kein natives<select>mehr ist. - Ein einzelner Termin im Stundenraster trägt kein Artzeichen — anders als derselbe Termin im Monat oder in der Agenda (seit dem 23.09.2026, N134, dort ergänzt). Die Woche ist seit dem 22.09.2026 die Hauptansicht, und ihre Blöcke (
calendar/client/Stundenraster.tsx,Block/Ganztagsblock) färben nach wie vor nur über die linke Kante. Nicht angefasst, weil die Runde vom 23.09.2026 diese Stelle nicht in ihrem Zuschnitt hatte — nur die Kollisionswarnung „doppelt" dort ist erledigt (Punkt 6 oben). Für dieselbe Konsistenz wie im Monat fehlt noch einterminZeichen()-Aufruf vor dem Titel jedes Blocks.