From 353a9b9316f2cf472c72b6e970efb3b8fea218d8 Mon Sep 17 00:00:00 2001 From: TheMeinerLP Date: Tue, 29 Sep 2026 15:23:10 +0200 Subject: [PATCH] docs(openspec): archive seasonal-lobby-world Claude-Session: https://claude.ai/code/session_01A7aAe2E6wAEbi6jjnyPTWH --- .../.openspec.yaml | 0 .../design.md | 0 .../proposal.md | 0 .../specs/app-variants/spec.md | 0 .../specs/lobby-seasons/spec.md | 0 .../2026-09-29-seasonal-lobby-world}/tasks.md | 2 +- openspec/specs/app-variants/spec.md | 8 +- openspec/specs/lobby-seasons/spec.md | 123 ++++++++++++++++++ 8 files changed, 130 insertions(+), 3 deletions(-) rename openspec/changes/{seasonal-lobby-world => archive/2026-09-29-seasonal-lobby-world}/.openspec.yaml (100%) rename openspec/changes/{seasonal-lobby-world => archive/2026-09-29-seasonal-lobby-world}/design.md (100%) rename openspec/changes/{seasonal-lobby-world => archive/2026-09-29-seasonal-lobby-world}/proposal.md (100%) rename openspec/changes/{seasonal-lobby-world => archive/2026-09-29-seasonal-lobby-world}/specs/app-variants/spec.md (100%) rename openspec/changes/{seasonal-lobby-world => archive/2026-09-29-seasonal-lobby-world}/specs/lobby-seasons/spec.md (100%) rename openspec/changes/{seasonal-lobby-world => archive/2026-09-29-seasonal-lobby-world}/tasks.md (97%) create mode 100644 openspec/specs/lobby-seasons/spec.md diff --git a/openspec/changes/seasonal-lobby-world/.openspec.yaml b/openspec/changes/archive/2026-09-29-seasonal-lobby-world/.openspec.yaml similarity index 100% rename from openspec/changes/seasonal-lobby-world/.openspec.yaml rename to openspec/changes/archive/2026-09-29-seasonal-lobby-world/.openspec.yaml diff --git a/openspec/changes/seasonal-lobby-world/design.md b/openspec/changes/archive/2026-09-29-seasonal-lobby-world/design.md similarity index 100% rename from openspec/changes/seasonal-lobby-world/design.md rename to openspec/changes/archive/2026-09-29-seasonal-lobby-world/design.md diff --git a/openspec/changes/seasonal-lobby-world/proposal.md b/openspec/changes/archive/2026-09-29-seasonal-lobby-world/proposal.md similarity index 100% rename from openspec/changes/seasonal-lobby-world/proposal.md rename to openspec/changes/archive/2026-09-29-seasonal-lobby-world/proposal.md diff --git a/openspec/changes/seasonal-lobby-world/specs/app-variants/spec.md b/openspec/changes/archive/2026-09-29-seasonal-lobby-world/specs/app-variants/spec.md similarity index 100% rename from openspec/changes/seasonal-lobby-world/specs/app-variants/spec.md rename to openspec/changes/archive/2026-09-29-seasonal-lobby-world/specs/app-variants/spec.md diff --git a/openspec/changes/seasonal-lobby-world/specs/lobby-seasons/spec.md b/openspec/changes/archive/2026-09-29-seasonal-lobby-world/specs/lobby-seasons/spec.md similarity index 100% rename from openspec/changes/seasonal-lobby-world/specs/lobby-seasons/spec.md rename to openspec/changes/archive/2026-09-29-seasonal-lobby-world/specs/lobby-seasons/spec.md diff --git a/openspec/changes/seasonal-lobby-world/tasks.md b/openspec/changes/archive/2026-09-29-seasonal-lobby-world/tasks.md similarity index 97% rename from openspec/changes/seasonal-lobby-world/tasks.md rename to openspec/changes/archive/2026-09-29-seasonal-lobby-world/tasks.md index abbb7dfe..4ef00dfd 100644 --- a/openspec/changes/seasonal-lobby-world/tasks.md +++ b/openspec/changes/archive/2026-09-29-seasonal-lobby-world/tasks.md @@ -47,4 +47,4 @@ Jeder Agent-Prompt nennt die Regeln, die für seinen Task gelten: erst Vorhanden ## 5. Pull Request -- [ ] 5.1 Pull Request vom Integrationszweig auf `main` unter dem Titel `feat(season): restart the lobby into a seasonal world during its window` öffnen (Titel und Beschreibung Englisch), mit dem Hinweis, dass er PR #225 ersetzt und die Abwägung Neustart statt Live-Wechsel enthält; nach dem Merge PR #225 mit einem Kommentar schließen, der auf den neuen PR verweist (superseded). Nachweis: PR-URL, CI grün. +- [x] 5.1 Pull Request vom Integrationszweig auf `main` unter dem Titel `feat(season): restart the lobby into a seasonal world during its window` öffnen (Titel und Beschreibung Englisch), mit dem Hinweis, dass er PR #225 ersetzt und die Abwägung Neustart statt Live-Wechsel enthält; PR #225 wurde vor dem Merge mit einem Kommentar geschlossen, der auf den neuen PR verweist (superseded). Nachweis: PR-URL, CI grün. diff --git a/openspec/specs/app-variants/spec.md b/openspec/specs/app-variants/spec.md index eb6d9e0e..ecbd0a49 100644 --- a/openspec/specs/app-variants/spec.md +++ b/openspec/specs/app-variants/spec.md @@ -14,7 +14,7 @@ Titan MUSS für jede Betriebsumgebung als eigene, allein startbare Variante geba #### Scenario: Entwicklungsvariante startet - **WHEN** ein Entwickler das Jar der Variante `local` ohne CloudNet startet -- **THEN** startet die Lobby mit denselben Funktionen wie die Variante `cloudnet` +- **THEN** startet die Lobby mit denselben Funktionen wie die Variante `cloudnet`, außer denen einer Column, die nur `cloudnet` enthält ### Requirement: Eine Variante startet nur mit allen erwarteten Columns Jede Variante MUSS festlegen, welche Columns sie enthält. Beim Start MUSS die Lobby prüfen, dass jede erwartete Column geladen ist. Fehlt eine, DARF die Lobby NICHT starten, und die Fehlermeldung MUSS die fehlende Column nennen. @@ -28,7 +28,7 @@ Jede Variante MUSS festlegen, welche Columns sie enthält. Beim Start MUSS die L - **THEN** startet die Lobby und meldet jede Column als gestartet ### Requirement: Varianten verhalten sich wie die bisherige Lobby -Solange sich die Varianten nur im Namen unterscheiden, MÜSSEN beide Varianten dieselben Columns enthalten und sich für Spieler und Betreiber genauso verhalten wie die bisherige einzelne Lobby: gleiche Features, gleiche Konfigurationsschlüssel, gleiche Befehle, gleiche Texte. +Solange sich die Varianten nur im Namen unterscheiden, MÜSSEN beide Varianten dieselben Columns enthalten und sich für Spieler und Betreiber genauso verhalten wie die bisherige einzelne Lobby: gleiche Features, gleiche Konfigurationsschlüssel, gleiche Befehle, gleiche Texte. Eine Column, die einen Dienst-Supervisor zum Neustart braucht, wie `season`, ist nur in `cloudnet` enthalten; die Variante `local` DARF sie auslassen, und ihre Konfigurationsschlüssel gelten dort nicht. #### Scenario: Gleiches Verhalten nach dem Umbau - **WHEN** ein Spieler die Lobby der Variante `cloudnet` betritt, den Navigator nutzt, sitzt, kitzelt und mit der Elytra fliegt @@ -38,6 +38,10 @@ Solange sich die Varianten nur im Namen unterscheiden, MÜSSEN beide Varianten d - **WHEN** ein Betreiber seine bisherige `application.yaml` unverändert neben das Jar der Variante legt - **THEN** übernimmt die Lobby alle Werte daraus wie vorher +#### Scenario: Saison-Column nur in der Produktionsvariante +- **WHEN** die Variante `local` mit einer `application.yaml` startet, die `seasons.*` enthält +- **THEN** lädt sie keine Saison-Column, wählt die Standardwelt und stoppt nie wegen einer Saison, während `cloudnet` die Column enthält und ihr Start sie als erwartete Column prüft + ### Requirement: Standardwerte kommen aus den Columns der Variante Jede Column MUSS ihre eigenen Standardwerte mitbringen. Die Variante MUSS die Standardwerte aller ihrer Columns ausliefern und für Betreiber einsehbar als eine kommentierte Beispieldatei neben das Jar legen. Beanspruchen zwei Columns denselben Konfigurationsschlüssel, MUSS der Build fehlschlagen und beide Columns nennen. diff --git a/openspec/specs/lobby-seasons/spec.md b/openspec/specs/lobby-seasons/spec.md new file mode 100644 index 00000000..f864cff4 --- /dev/null +++ b/openspec/specs/lobby-seasons/spec.md @@ -0,0 +1,123 @@ +# lobby-seasons Specification + +## Purpose +Legt fest, wie die Lobby in einem konfigurierten Zeitfenster in einer eigenen Saisonwelt läuft: Die Welt wird beim Start gewählt, ein nötiger Wechsel wird nur über einen Neustart bei leerer Lobby vollzogen, und ungültige Konfiguration verhindert den Start. + +## Requirements + +### Requirement: Die Welt wird beim Start nach dem aktiven Saisonfenster gewählt +Beim Start MUSS die Lobby die Welt der aktiven Saison laden. Eine Saison ist aktiv, wenn `seasons..enabled` wahr ist und die aktuelle Zeit der konfigurierten Zeitzone im Fenster von `seasons..from` (einschließlich) bis `seasons..to` (ausschließlich) liegt. Die Welt ist das Verzeichnis unter `worlds/`, das `seasons..world` nennt, mit seiner eigenen Map-Datei (Spawn). `seasons..enabled` MUSS standardmäßig wahr sein. Die Zeitzone MUSS über `seasons.zone` einstellbar sein und standardmäßig `Europe/Berlin` lauten. + +#### Scenario: Fenster ist aktiv +- **WHEN** die Saison `winter` auf die Welt `winter` zeigt, ihr Fenster die aktuelle Zeit enthält und die Lobby startet +- **THEN** lädt die Lobby `worlds/winter` und spawnt Spieler an dessen Map-Spawn + +#### Scenario: Fenster ist noch nicht erreicht oder vorbei +- **WHEN** die aktuelle Zeit vor `from` oder ab `to` einer Saison liegt und die Lobby startet +- **THEN** lädt die Lobby die Standardwelt (`-DTITAN_LOBBY_MAP`, sonst `world`) + +#### Scenario: Fensterende ist ausgeschlossen +- **WHEN** die aktuelle Zeit genau `to` einer Saison entspricht +- **THEN** gilt die Saison als nicht aktiv + +#### Scenario: Zeitzone bestimmt das Fenster +- **WHEN** `seasons.zone` auf `Asia/Tokyo` steht und `from` lokal in Tokio erreicht ist, in Berlin aber noch nicht +- **THEN** gilt die Saison als aktiv + +### Requirement: Ohne aktive Saison gilt das bisherige Verhalten +Ist keine Saison konfiguriert oder keine aktiv, MUSS die Lobby die Welt wie bisher wählen. Eine Konfiguration ohne `seasons.*` DARF sich für Spieler und Betreiber nicht verändern. + +#### Scenario: Keine Saison konfiguriert +- **WHEN** die Konfiguration keinen Abschnitt `seasons` enthält +- **THEN** lädt die Lobby die Standardwelt und merkt keinen Neustart vor + +### Requirement: Der Abschalter wirkt ohne Konfigurations-Neustart +`seasons..enabled` MUSS live gelesen werden, sodass eine Änderung über die Konfigurationsüberwachung ohne Neustart der Lobby wirkt. Eine abgeschaltete Saison MUSS bei der Bestimmung der gewünschten Welt so behandelt werden, als wäre sie nicht konfiguriert. + +#### Scenario: Abschalten während der Saison +- **WHEN** die Lobby in der Welt der Saison `winter` läuft und `seasons.winter.enabled` auf `false` gesetzt wird +- **THEN** ist die gewünschte Welt die Standardwelt, und ein Neustart ist vorgemerkt + +#### Scenario: Einschalten im Fenster +- **WHEN** die Lobby in der Standardwelt läuft und `seasons.winter.enabled` im aktiven Fenster auf `true` gesetzt wird +- **THEN** ist die gewünschte Welt die Welt von `winter`, und ein Neustart ist vorgemerkt + +### Requirement: Ein Neustart ist nur vorgemerkt, wenn gewünschte und gestartete Welt abweichen +Die Lobby MUSS die gewünschte Welt mindestens einmal pro Minute mit der Welt vergleichen, mit der sie gestartet ist. Weichen beide ab, MUSS ein Neustart vorgemerkt sein; das MUSS einmal pro Vormerkung mit der Saison und dem Zeitpunkt geloggt werden. Stimmen beide wieder überein, MUSS die Vormerkung aufgehoben werden. Die Lobby DARF die Welt zur Laufzeit NICHT wechseln. + +#### Scenario: Saisonbeginn erreicht +- **WHEN** die Lobby in der Standardwelt läuft und das Fenster der Saison `winter` beginnt +- **THEN** ist spätestens nach einer Minute ein Neustart für `winter` vorgemerkt, und die Meldung erscheint einmal + +#### Scenario: Saisonende erreicht +- **WHEN** die Lobby in der Welt von `winter` läuft und das Fenster endet +- **THEN** ist spätestens nach einer Minute ein Neustart vorgemerkt, mit der Standardwelt als Ziel + +#### Scenario: Vormerkung wird aufgehoben +- **WHEN** ein Neustart vorgemerkt ist und die gewünschte Welt wieder der gestarteten entspricht, etwa weil der Abschalter zurückgesetzt wurde +- **THEN** ist kein Neustart mehr vorgemerkt, und die Lobby stoppt nicht + +#### Scenario: Kein Neustart-Kreislauf +- **WHEN** die Lobby nach einem Neustart in der gewünschten Welt läuft +- **THEN** ist kein Neustart vorgemerkt + +#### Scenario: Meldung nicht wiederholt +- **WHEN** ein Neustart vorgemerkt bleibt und die Minuten-Prüfung mehrfach läuft +- **THEN** wird die Vormerkung nicht erneut geloggt + +### Requirement: Die Lobby stoppt nur, wenn sie leer ist +Ist ein Neustart vorgemerkt und sind keine Spieler online, MUSS die Lobby sauber stoppen, damit der Dienst-Supervisor sie neu startet. Die Prüfung MUSS im Minutentakt und nach jedem Verlassen eines Spielers laufen, wobei der ausscheidende Spieler nicht mehr mitzählt. Die Lobby DARF NICHT stoppen, solange ein Spieler online ist. Es gibt keine Obergrenze für das Warten. + +#### Scenario: Leere Lobby im Minutentakt +- **WHEN** ein Neustart vorgemerkt ist und beim Minutentakt kein Spieler online ist +- **THEN** stoppt die Lobby sauber + +#### Scenario: Letzter Spieler geht +- **WHEN** ein Neustart vorgemerkt ist und der letzte Spieler die Lobby verlässt +- **THEN** stoppt die Lobby, ohne den nächsten Minutentakt abzuwarten + +#### Scenario: Spieler online +- **WHEN** ein Neustart vorgemerkt ist und mindestens ein Spieler online ist +- **THEN** stoppt die Lobby nicht, auch nicht nach vielen Minutentakten + +#### Scenario: Ein Spieler geht, andere bleiben +- **WHEN** ein Neustart vorgemerkt ist und einer von zwei Spielern die Lobby verlässt +- **THEN** stoppt die Lobby nicht + +#### Scenario: Nichts vorgemerkt +- **WHEN** kein Neustart vorgemerkt ist und die Lobby leer ist +- **THEN** stoppt die Lobby nicht + +### Requirement: Überlappende Fenster ergeben genau eine Welt +Überlappen sich die Fenster aktiver Saisons, MUSS die Saison mit dem früheren `from` gelten; bei gleichem `from` die mit der alphabetisch kleineren Id. Die Lobby MUSS die Überlappung beim Start als Warnung mit beiden Ids loggen und darf deswegen nicht abbrechen. + +#### Scenario: Zwei Fenster überlappen +- **WHEN** `autumn` ab 1. Oktober und `halloween` ab 25. Oktober gelten und beide am 28. Oktober aktiv wären +- **THEN** ist `autumn` die gewünschte Saison, und beim Start steht eine Warnung mit `autumn` und `halloween` im Log + +### Requirement: Ungültige Saison-Konfiguration verhindert den Start +Ist eine aktivierte Saison ungültig, MUSS die Lobby den Start abbrechen, und die Fehlermeldung MUSS den vollständigen Schlüssel (`seasons..`) und den Grund nennen. Ungültig sind ein fehlender `world`-, `from`- oder `to`-Wert, ein Datum, das sich nicht lesen lässt, `from` nicht vor `to`, ein Weltverzeichnis, das unter `worlds/` fehlt, und ein Weltverzeichnis ohne Map-Datei. Auch eine ungültige `seasons.zone` MUSS den Start abbrechen. Eine abgeschaltete Saison DARF den Start nicht verhindern. Ein zur Laufzeit ungültig gewordener Wert DARF weder einen Neustart auslösen noch die Lobby stoppen; er MUSS als Warnung geloggt werden, und die Lobby behält bis zur Korrektur ihren Zustand: kein Neustart wird vorgemerkt, und es gibt keinen Stopp. + +#### Scenario: Welt existiert nicht +- **WHEN** `seasons.winter.world` auf `winter` zeigt und `worlds/winter` fehlt +- **THEN** startet die Lobby nicht und nennt `seasons.winter.world` und den Grund + +#### Scenario: Welt ohne Map-Datei +- **WHEN** `worlds/winter` existiert, enthält aber keine Map-Datei +- **THEN** startet die Lobby nicht und nennt `seasons.winter.world` und den Grund + +#### Scenario: Datum nicht lesbar +- **WHEN** `seasons.winter.from` den Wert `morgen` hat +- **THEN** startet die Lobby nicht und nennt `seasons.winter.from` + +#### Scenario: Fenster verkehrt herum +- **WHEN** `seasons.winter.from` nicht vor `seasons.winter.to` liegt +- **THEN** startet die Lobby nicht und nennt `seasons.winter.from` und `seasons.winter.to` + +#### Scenario: Abgeschaltete Saison mit fehlender Welt +- **WHEN** `seasons.winter.enabled` `false` ist und `worlds/winter` fehlt +- **THEN** startet die Lobby normal + +#### Scenario: Live aktivierte Saison ohne Welt +- **WHEN** die Lobby läuft und `seasons.winter.enabled` im aktiven Fenster auf `true` gesetzt wird, obwohl `worlds/winter` fehlt +- **THEN** merkt die Lobby keinen Neustart vor, loggt eine Warnung mit `seasons.winter.world` und läuft weiter