diff --git a/CHANGELOG.md b/CHANGELOG.md index c0c7b7d..2aab35a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,32 @@ die Versionierung folgt (in der aktuellen Doku-Phase) dem Dokumentationsstand de > erzeugt; MS-0 und MS-1 bleiben offen. ### Entschieden +- **D-108: Territorium wächst kriechend an jedem eigenen Bauanker.** Die Frage + aus Testbericht T-01 (#92) — erweitert ein zweites HQ den Baubereich? — war im + Code längst beantwortet und nie ausgesprochen: + `ConstructionSystem.BuildInfluenceRadiusCells = 8` misst ab **einem eigenen + Bauanker**, nicht ab dem HQ, also erweitert jedes fertige Gebäude die Zone um + seinen eigenen Radius. Das bleibt so und ist ab jetzt gewollte Mechanik: es ist + das klassische C&C-Verhalten und koppelt Expansion genau so an die Wirtschaft, + wie die Verknappung aus D-102 es verlangt. Die gemeldete Enge wird + **nicht** über den Radius beantwortet, sondern zuerst gemessen — Sprint 21 + Paket 21.1 liefert als Test, wie viele Gebäude bei + `MinimumBuildingDistanceCells` 2 gegen 1 gegen 0 in die Startzone passen, weil + dieser Wert Zellen *innerhalb* der Zone sperrt und die plausiblere Ursache ist +- **D-109: Die Kartenmitte wird ein Gebiet mit schmalen Zufahrten.** Feld 5 liegt + bei (62, 62) und trägt mit 15.000 AE zwei Drittel mehr als jedes andere — die + Absicht „die Mitte ist wertvoll" war getroffen, nur nicht ausgespielt. Aus dem + einen Feld werden vier bis sechs, und das Gelände formt die Zufahrten. + Verbindliche Auflage: **Begehbarkeit und Optik stammen aus einer einzigen + Struktur.** Heute tun sie das nicht — `CostField` kann unbegehbare Zellen + (`ImpassableCost = 255`), aber es schreibt niemand hinein ausser + `ConstructionSystem` für Gebäude-Footprints, während `GlutrinneBlockoutView` + rund 84 Felsen streut und im eigenen Docstring zusichert, nie in den + Simulationszustand zu schreiben — die Felsen sind Deko und begehbar. Zwei + Quellen ergäben Einheiten, die durch Felsen laufen und an unsichtbaren Wänden + hängenbleiben. Die Umsetzung bleibt beim Maintainer-Strang: + `CostField.SetCost` ist bereits öffentlich und wird aus `Gameplay/Match/` + aufgerufen, `Simulation/Pathfinding/` wird nicht angefasst - **D-105: Dennis Westermann (`@cubetribe`) führt das Projekt allein.** Er ist alleiniger Projektinhaber, Maintainer, Tier-Entscheider und Mergeberechtigter; Michael Falk (`@travelhawk`) bleibt historischer Autor und @@ -30,6 +56,16 @@ die Versionierung folgt (in der aktuellen Doku-Phase) dem Dokumentationsstand de spielerisch abgenommen und kein Meilenstein-Nachweis ### Hinzugefügt +- **Sprint 21 festgeplant und als Großauftrag erteilt.** Aus dem Vorschlag zu den + Verknappungsfolgen wird nach den Inhaberentscheidungen D-108 und D-109 die + Sprintdatei `docs/production/hashkrieg/21_Sprint_Verknappungsfolgen.md` mit + sieben Paketen (Restbestand sichtbar, Baubereich sichtbar, Auswahl ehrlich, + Startmenge gerechnet, Kartendichte, zentrale Zone) und der gebündelte Auftrag + `AUFTRAG_Verknappungsfolgen.md`, der Sprint 21 und danach Sprint 18 in eine + verbindliche Reihenfolge bringt. Beide sind gegen `main` @ `3e10c48` geprüft. + Nebenbei berichtigt: `AUFTRAG_Grossblock.md` behauptete, `dotnet test` laufe + lokal nicht — es läuft mit dem im Repo mitgelieferten `.dotnet/` (8.0.318, + exakt die in `global.json` gepinnte Version) in rund 14 Sekunden - **Testbericht T-01 vom 10.08.2026 (Build `4053c15`) zerlegt — zehn Issues (#85–#94) und ein Sprintvorschlag.** Der Bericht bewertet die mit #80 eingeführte AE-Verknappung und zeigt, dass diese eine Änderung acht weitere diff --git a/docs/production/DecisionLog.md b/docs/production/DecisionLog.md index 01d9e11..95f08f7 100644 --- a/docs/production/DecisionLog.md +++ b/docs/production/DecisionLog.md @@ -1,6 +1,6 @@ # Decision Log -**Version:** 1.39.0 | **Status:** aktiv (laufend) | **Verantwortungsbereich:** Game Director / Lead Technical Director / Project Owner | **Sprint:** 16 +**Version:** 1.40.0 | **Status:** aktiv (laufend) | **Verantwortungsbereich:** Game Director / Lead Technical Director / Project Owner | **Sprint:** 21 ## Zweck @@ -3429,6 +3429,113 @@ selbst. und Befehlsschemata bleiben unverändert. D-102 bleibt für Feldanzahl, Koordinaten, Reserven, Reihenfolge und Ernterate vollständig verbindlich. +### D-108 | verbindlich | Sprint 21 (Territorium wächst kriechend an jedem Bauanker) + +**Status:** Inhaberentscheidung vom 2026-08-17. + +**Kontext:** Testbericht T-01 (#92) fragt, wie der Spieler sein Territorium +erweitert — ob ein zweites HQ die Bauzone vergrößert, ob es später eigene +Erweiterungsgebäude gibt, ob Bauzonen sich überschneiden dürfen. Der Code +beantwortet die Frage bereits, ausgesprochen wurde sie nie: +`ConstructionSystem.BuildInfluenceRadiusCells = 8` misst die maximale +footprint-bewusste Chebyshev-Distanz **von einem eigenen Bauanker**, nicht vom +HQ. Damit erweitert jedes fertiggestellte Gebäude das erlaubte Feld um seinen +eigenen Radius; die Zone kriecht mit der Basis mit, statt sprunghaft an einem +zweiten HQ zu wachsen. Der Bericht meldet zugleich, der Platz sei „nach einigen +Kraftwerken relativ schnell ausgeschöpft" — wofür `MinimumBuildingDistanceCells = 2` +die wahrscheinlichere Ursache ist als der Radius, weil dieser Wert Zellen +*innerhalb* der Zone sperrt. + +**Alternativen:** + +1. Die bestehende Regel festschreiben: jedes eigene Gebäude bleibt Bauanker. +2. Nur ausgewiesene Gebäude (HQ, Raffinerie, ein künftiger Expansionsposten) + werden Anker; alle übrigen erweitern die Zone nicht. +3. Die Regel beibehalten und den Radius über 8 anheben. + +**Entscheidung:** Alternative 1. **Jedes eigene Gebäude bleibt Bauanker**, das +Kriechen ist gewollt und ab sofort ausgesprochene Mechanik. Die gemeldete Enge +wird **nicht** über den Radius beantwortet, sondern zuerst gemessen: Sprint 21 +Paket 21.1 liefert als Test, wie viele Gebäude welcher Footprintgröße bei +`MinimumBuildingDistanceCells` 2 gegen 1 gegen 0 in die Startzone passen. Erst +gegen diese Zahl wird über den Wert entschieden. + +**Begründung:** Das kriechende Wachstum ist das klassische C&C-Verhalten und +koppelt Expansion genau so an die Wirtschaft, wie die Verknappung aus D-102 es +verlangt: Wer ein entferntes Feld erschließen will, muss sich baulich dorthin +arbeiten. Alternative 2 wäre eine echte Designerweiterung mit eigenem +Gebäudetyp und gehört nicht in einen Sprint, der Bestehendes lesbar macht. +Alternative 3 behebt möglicherweise das falsche Problem — der Radius ist nicht +belegt als Ursache, die Mindestdistanz ist es plausibel. + +**Konsequenzen:** Der Docstring an `BuildInfluenceRadiusCells` wird so +umgeschrieben, dass die Ankerregel nicht mehr nur ein Nebensatz ist. Das +Baubereichs-Overlay (#91, Paket 21.4) färbt die **tatsächlich baubaren Zellen** +für den gewählten Footprint ein, nicht einen Radius-Ring — ein Ring wäre +unehrlich, weil er die innerhalb gesperrten Zellen verschweigt. Fällt +`MinimumBuildingDistanceCells` später nach der Messung, ist das ein eigener PR +mit eigener D-ID und bewegt `RulesHash64`. Die Kartendichte (#93, Paket 21.6) +hängt an dieser Festlegung und läuft danach. + +### D-109 | verbindlich | Sprint 21 (Die Kartenmitte wird ein Gebiet mit Chokepoints) + +**Status:** Inhaberentscheidung vom 2026-08-17. + +**Kontext:** Testbericht T-01 (#94) schlägt vor, im Zentrum eine größere +abgeschlossene Zone mit vier bis sechs Aetheriumvorkommen anzulegen, von allen +vier Seiten erreichbar, aber jeweils über schmale Zufahrten. Wer die Mitte +kontrolliert, erhält einen wirtschaftlichen Vorteil und kann die Position +befestigen — die Karte erzeugt damit einen Konfliktpunkt, ohne ihn +vorzuschreiben. Die Absicht ist bereits getroffen und nur nicht ausgespielt: +Feld 5 liegt bei (62, 62) und trägt mit 15.000 AE zwei Drittel mehr als jedes +andere Feld. Ein einzelnes Feld ist aber kein Gebiet, und ohne Chokepoints ist +es auch keine haltbare Position. + +Am Code geprüft (`main` @ `3e10c48`): `CostField` unterstützt unbegehbares +Gelände vollständig (`OpenCost = 1`, `ImpassableCost = 255`, Zwischenwerte für +schweren Grund), aber der Konstruktor füllt alles mit `OpenCost` und es schreibt +**niemand** hinein außer `ConstructionSystem` für Gebäude-Footprints. Die Optik +weiß davon nichts: `GlutrinneBlockoutView` streut rund 84 Felsen mit festem Seed +und sichert im eigenen Docstring zu, nie in den Simulationszustand zu schreiben — +die Felsen sind Deko und begehbar. + +**Alternativen:** + +1. Zone und Chokepoints bauen, mit einer autoritativen Geländequelle für + Simulation und Optik. +2. Nur die Kartenlage ändern (vier bis sechs Felder gruppieren), auf Gelände + verzichten. +3. Zurückstellen, bis die KI ein Gebiet bestreiten kann. + +**Entscheidung:** Alternative 1. Die Mitte wird ein Gebiet mit schmalen +Zufahrten. Verbindliche Auflage: **Begehbarkeit und Optik stammen aus einer +einzigen Struktur** — die kanonische Kartenlage in `MatchBootstrap` hält das +Gelände so, wie sie heute schon die fünf Aetheriumfelder hält; die Simulation +schreibt es über die bestehende öffentliche `CostField.SetCost`, die +Blockout-View baut sich daraus. Zwei getrennte Quellen sind ausdrücklich +untersagt. + +**Begründung:** Zwei Quellen ergeben Einheiten, die durch sichtbare Felsen +laufen und an unsichtbaren Wänden hängenbleiben — ein Fehlerbild, das später +niemand mehr der Kartenarbeit zuordnet. Alternative 2 nimmt dem Vorschlag genau +das, was ihn trägt: ohne Chokepoints ist eine reiche Mitte kein Halteproblem, +sondern nur ein größerer Wettlauf. Alternative 3 verschiebt die Kartenarbeit +hinter fremde Sprintplanung, obwohl die Karte auch ohne kluge KI zwischen zwei +Menschen gespielt wird. + +**Konsequenzen:** Die Umsetzung bleibt in der Schreibhoheit des +Maintainer-Strangs: `Gameplay/Match/` und `Presentation/Maps/` werden +bearbeitet, `Simulation/Pathfinding/` **nicht** — `CostField.SetCost` ist +bereits öffentlich und wird von `Gameplay/Match/` aus aufgerufen, wie +`PathfindingTestBootstrap` es vorführt. Die Symmetrieauflage aus D-107 gilt +unverändert. Ein Erreichbarkeitstest über das `FlowField` gehört in +`tools/Nova.SimRunner.Tests/`, damit eine spätere Kartenänderung keine Basis +unbemerkt einsperrt. Die Änderung bewegt die Determinismus-Baselines **und** den +gepinnten Ausgang der kanonischen KI-Partie, der dem Einheitenstrang gehört — +sie braucht deshalb ein eigenes, mit dem Einheitenstrang abgestimmtes +Merge-Fenster. Verteidigungsbalance an den Zufahrten und KI-Verhalten in der +Mitte sind ausdrücklich nicht Teil dieser Entscheidung. + ## Offene Punkte - Alle Sprint-4-Review-Befunde (105, davon 9 kritisch): 7 entscheidungsbedürftige kritische Befunde sind durch D-043–D-052 entschieden. @@ -3509,6 +3616,7 @@ Koordinaten, Reserven, Reihenfolge und Ernterate vollständig verbindlich. | Version | Datum | Änderung | Autor | |---|---|---|---| +| 1.40.0 | 2026-08-17 | D-108 und D-109 aufgenommen (Sprint 21, aus Testbericht T-01): Territorium wächst **kriechend an jedem eigenen Bauanker** — die bestehende Regel wird festgeschrieben statt geändert, und die gemeldete Enge wird an `MinimumBuildingDistanceCells` gemessen, bevor ein Wert fällt. Die Kartenmitte wird ein Gebiet mit schmalen Zufahrten, mit der verbindlichen Auflage, dass Begehbarkeit und Optik aus **einer** Struktur stammen — heute streut `GlutrinneBlockoutView` begehbare Deko-Felsen, während niemand ausser `ConstructionSystem` in das `CostField` schreibt | Dennis Westermann / Orchestrator | | 1.39.0 | 2026-08-10 | D-107 aufgenommen: Die bestehende Glutrinne-Layoutachse spiegelt Punkte um 124 und 3×3-Footprint-Ursprünge abgeleitet um 122; der zweite HQ-Ursprung wird von `(120,120)` auf `(118,118)` korrigiert | Agent (unter Delegation) / Dennis Westermann | | 1.38.0 | 2026-08-10 | D-104 aufgenommen: footprintbasierte Chebyshev-Platzierung mit Einfluss-, Feld-, Gelände- und Gebäudeabständen, zustandslose kumulative Reparaturkosten von 30 Prozent, kanonisch dichte Reparaturreihenfolge und Rules-Revision V3 | Project Owner / Agent (unter Delegation) | | 1.37.0 | 2026-08-10 | D-103 aufgenommen: Bauvoraussetzungen werden eine fraktionsgleiche All-of-Maske über unveränderte `UnitRole`-Wirewerte; Hash-, Fail-Closed-, Plattformmodul- und KI-Handoff-Folgen festgeschrieben | Agent (unter Delegation) / Dennis Westermann | diff --git a/docs/production/hashkrieg/21_Sprint_Verknappungsfolgen.md b/docs/production/hashkrieg/21_Sprint_Verknappungsfolgen.md new file mode 100644 index 0000000..bb2f8ff --- /dev/null +++ b/docs/production/hashkrieg/21_Sprint_Verknappungsfolgen.md @@ -0,0 +1,395 @@ +# Sprint 21: Die Folgen der Verknappung — endliche Felder werden lesbar und bespielbar + +**Version:** 1.0.0 | **Status:** geplant | **Verantwortungsbereich:** Maintainer-Strang | **Sprint:** 21 | **Vorgänger:** [16_Sprint_Wirtschaft.md](16_Sprint_Wirtschaft.md) | **Parallel zu:** [13B](13B_Sprint_Einheitenverhalten.md) | **Regelwerk:** [13-15_Parallelbetrieb.md](13-15_Parallelbetrieb.md) | **UX-Gate:** human | **Leitsatz:** endliche Felder sind kein Wert, sondern ein Systemwechsel + +## Zweck + +Mit [#80](https://github.com/VibecodingGermany/HashKrieg/pull/80) bekamen die +Aetheriumfelder eine endliche Reserve. Der Testbericht T-01 vom 10.08.2026 +zeigt, dass diese eine Änderung acht weitere Systeme betrifft, die noch auf der +alten Annahme unendlicher Vorkommen stehen. Dieser Sprint zieht sie nach. + +Er tut dabei **drei verschiedene Dinge**, und die Unterscheidung ist wichtig: + +1. Er macht **sichtbar**, was die Simulation längst exakt weiß (Restbestand, + Baubereich, Auswahlinhalt). Kein neues Verhalten, nur der Weg nach außen. +2. Er **spricht aus**, was der Code bereits entscheidet, ohne dass es je + festgelegt wurde (Territoriumswachstum). Eine Festlegung, keine Umsetzung. +3. Er **ändert die Karte** — Felddichte und die Mitte als Gebiet. Das ist die + einzige echte Verhaltensänderung des Sprints und die teuerste. + +## Herkunft dieser Datei + +Aus dem [Vorschlag zur Sprintbildung](20_Vorschlag_Verknappungsfolgen.md), +geschnitten aus [Testbericht T-01](Testberichte/2026-08-10_4053c15_T-01.md) +(Build `4053c15`). Der Vorschlag war ausdrücklich kein Sprint; diese Datei ist +die Festplanung nach den Inhaberentscheidungen vom 2026-08-17 +(**D-108** Territorium, **D-109** zentrale Zone). + +Ein Befund des Vorschlags ist bereits erledigt: **#85** (KI-Livelock auf dem +leeren Feld) wurde vom Einheitenstrang in +[#97](https://github.com/VibecodingGermany/HashKrieg/pull/97) behoben und ist +geschlossen. Die Vertragsflächen **#89** und **#90** (Patrouille, Bewachen) +bleiben ausdrücklich draußen — Begründung unter „Bewusst nicht in diesem Sprint". + +## Ausgangslage — am Code geprüft + +Alles hier ist gegen `main` @ `3e10c48` verifiziert. + +**Der Restbestand existiert exakt und kommt nirgends an.** `AetheriumField.RemainingAE` +ist monoton fallend, `IsExhausted` ist definiert, `EconomySystem` führt beides +sauber über den Snapshot. Die einzige Stelle, die ihn für einen Menschen liest, +ist `Presentation/UI/DebugHud.cs` — und das Debug-HUD ist kein Spiel-UI. Im +Match sind Felder nur *Ziel* eines Harvest-Befehls (`RtsDeviceInput`), kein +anklickbares Objekt mit eigenem Zustand. + +**`AetheriumField` kennt keine Anfangsreserve.** Eine Anzeige „6.420 / 9.000" +braucht den Sollwert. Ihn als Feld in den Zustand zu legen wäre eine +Layoutänderung an `Simulation/State/` — **eingefroren**, D-ID-pflichtig, und für +diesen Zweck unnötig: die Anfangsreserve steht in der kanonischen Kartenlage und +ist von dort ableitbar. Siehe Paket 21.2. + +**Die Baubereichsregel ist scharf und unsichtbar.** In +`Simulation/Construction/ConstructionSystem.cs` gilt seit D-104: + +```csharp +public const int BuildInfluenceRadiusCells = 8; // ab JEDEM eigenen Bauanker +public const int MinimumBuildingDistanceCells = 2; // sperrt Zellen INNERHALB der Zone +``` + +Der Spieler erfährt beides nur durch Ablehnung. Seit #83 bekommt er immerhin den +Grund genannt — aber erst nach dem Fehlversuch und ohne zu sehen, wo es ginge. + +**Die Befehlskarte liest nur die Führungseinheit.** `CommandCardHud.BuildModel` +nimmt `selected[0]`, fragt `GetUnitCommands(faction, leadRole)` und hängt +`(+N weitere)` an den Titel. Die angebotenen Befehle hängen damit von der +*Reihenfolge* der Auswahl ab, nicht von ihrem Inhalt. + +**Die Karte kennt kein natürliches Gelände.** `CostField` unterstützt es +vollständig — `OpenCost = 1`, `ImpassableCost = 255`, Zwischenwerte 2..254 für +schweren Grund. Aber es schreibt **niemand** hinein außer +`ConstructionSystem` (Gebäude-Footprints) und einem Test-Bootstrap. Der +`CostField`-Konstruktor füllt alles mit `OpenCost`. + +Und die Optik weiß davon nichts: `Presentation/Maps/GlutrinneBlockoutView` +streut ~84 Felsen mit festem Seed und schreibt laut eigener Zusicherung +*„never writes into simulation state"* — die Felsen sind Deko und begehbar. +**Wer Chokepoints baut, muss beide Seiten aus derselben Quelle speisen**, sonst +laufen Einheiten durch Felsen und bleiben an unsichtbaren Wänden stehen. Das ist +der eigentliche Inhalt von Paket 21.7. + +**Die Feldlage steht viermal literal im Repo** (siehe „Risiken"). + +## Schreibhoheit + +Dieser Sprint gehört dem **Maintainer-Strang**. Er fasst keine Datei des +Einheitenstrangs an. + +**Erlaubt:** + +``` +Assets/_Project/Scripts/Gameplay/Match/ MatchBootstrap, Kartenlage, Gelände +Assets/_Project/Scripts/Gameplay/UI/ SelectionManager +Assets/_Project/Scripts/Simulation/Economy/ nur lesend erweitern, kein Layout +Assets/_Project/Scripts/Simulation/Construction/ nur Konstanten, siehe 21.1 +Assets/_Project/Scripts/Presentation/ Maps, UI, Overlays +tools/Nova.SimRunner/ Determinismus-Drehbuch +tools/Nova.SimRunner.Tests/ eigene neue Tests +``` + +**Verboten — gehört dem Einheitenstrang (13B):** + +``` +Assets/_Project/Scripts/Simulation/Combat/ +Assets/_Project/Scripts/Simulation/Movement/ +Assets/_Project/Scripts/Simulation/Factions/ +Assets/_Project/Scripts/Simulation/Pathfinding/ +Assets/_Project/Scripts/AI/ Assets/_Project/Scripts/AI.Data/ +Assets/_Project/Scripts/Presentation/UI/DebugHud.cs +tools/Nova.AiLab/ tools/Nova.AiLab.Tests/ +``` + +> **Die eine Feinheit, die Paket 21.7 möglich macht:** Gelände wird über die +> **bestehende öffentliche** `CostField.SetCost` aus `Gameplay/Match/` +> geschrieben — genau so, wie es `PathfindingTestBootstrap` heute schon tut. +> `Simulation/Pathfinding/` selbst wird **nicht angefasst**. Die Schreibhoheit +> bleibt damit gewahrt. Was 21.7 trotzdem auslöst, ist eine *Wirkung* auf den +> Einheitenstrang — die KI läuft danach über eine andere Karte, ihr gepinnter +> Ausgang bewegt sich. Das ist eine Absprache- und Merge-Fenster-Frage, keine +> Hoheitsfrage. Siehe „Risiken". + +**Eingefroren, D-ID-pflichtig, in diesem Sprint nicht angefasst:** + +``` +Simulation/CommandsV1/ kein neuer CommandKind +Simulation/Snapshots/ Simulation/Replays/ Simulation/Systems/ +Simulation/State/ Layout und Serialisierung +``` + +## Pakete + +Die Reihenfolge ist nach Abhängigkeit sortiert, nicht nach Aufwand. Jedes Paket +ist ein eigener PR und für sich abnehmbar. + +### 21.1 · Die Territoriumsregel wird ausgesprochen und gemessen (#92 → D-108) + +**Kein Overlay, keine Regeländerung — erst eine Festlegung und eine Zahl.** + +Die Entscheidung ist getroffen (D-108): **jedes eigene Gebäude bleibt Bauanker**, +die Zone kriecht mit der Basis mit. Das ist klassisches C&C und koppelt Expansion +genau so an die Wirtschaft, wie die Verknappung es will. Was fehlt, ist, dass es +irgendwo steht. + +Zu liefern: + +1. Den Docstring an `BuildInfluenceRadiusCells` so umschreiben, dass die Regel + *„ab jedem eigenen Bauanker"* nicht mehr nur ein Nebensatz ist, mit Verweis + auf D-108. +2. **Die Enge messen, bevor irgendetwas gedreht wird.** Der Bericht sagt, der + Platz sei „nach einigen Kraftwerken relativ schnell ausgeschöpft". Die + Vermutung aus #91 ist, dass nicht der Radius 8 die Ursache ist, sondern + `MinimumBuildingDistanceCells = 2`, das Zellen *innerhalb* der Zone sperrt. + Liefere eine Zahl, kein Gefühl: **wie viele Gebäude welcher Footprintgrößen + passen in die Startzone**, bei `MinimumBuildingDistanceCells` 2 gegen 1 + gegen 0? Als Test in `tools/Nova.SimRunner.Tests/`, damit die Zahl nicht + verfällt. +3. **Erst dann** entscheiden, ob der Wert fällt. Fällt er, ist das eine + Simulationsänderung mit eigenem PR und eigener Baseline-Bewegung — und der + Grund steht in der PR-Beschreibung mit alter und neuer Zahl. + +**Fertig wenn:** die Regel dokumentiert ist, die Kapazitätszahl als Test +existiert, und die Entscheidung über `MinimumBuildingDistanceCells` mit Zahl +begründet ist. + +### 21.2 · Der Restbestand wird sichtbar (#86) — **kritisch** + +Der wichtigste Punkt des Sprints. Ohne ihn bleibt die Verknappung eine +unsichtbare technische Mechanik. + +Zwei Dinge, die zusammengehören: + +**a) Das Vorkommen wird anklickbar und zeigt seine Zahl.** Auswahl eines Feldes +in `RtsDeviceInput`, Anzeige in der Befehlskarte im Format des Berichts: +`Aetherium-Vorkommen — 6.420 / 9.000 AE`. + +> **Den Sollwert nicht in den Zustand legen.** `AetheriumField` bekommt **kein** +> neues Feld — das wäre `Simulation/State/`-Layout und damit eingefroren. Die +> Anfangsreserve steht in der kanonischen Kartenlage (`MatchBootstrap.FieldLayouts`) +> und wird von dort gelesen. Ein Feld, das der Präsentation gehört, ist die +> richtige Ablage für eine Zahl, die die Präsentation braucht. + +**b) Die Karte liest sich ohne Klick.** Ein volles Vorkommen besteht heute aus +etwa sieben blauen Kristallen (`GlutrinneBlockoutView`). Sie verschwinden +schrittweise mit sinkendem Bestand (7 → 6 → … → leer), und ein erschöpftes Feld +ist eindeutig als erschöpft erkennbar — nicht nur „leer", sondern sichtbar +verbraucht. + +> Die Stufung ist reine Präsentation und **darf keine Simulationsabfrage pro +> Frame** werden. Der Kristallstand folgt `RemainingAE` über dieselbe Leseschiene +> wie das übrige HUD. + +**Fertig wenn:** ein Vorkommen anklickbar ist, Rest und Anfangsreserve zeigt, und +sein Kristallstand im laufenden Match sichtbar abnimmt. + +### 21.3 · Die Startmenge wird gerechnet, nicht geraten (#87) + +**Erst nach 21.2**, sonst wird wieder geschätzt. Der Tester lag um fast die +Hälfte daneben (schätzte 5.000, es sind 9.000) — genau weil es keine Anzeige gab. + +Die Frage ist nicht „9.000 oder 10.000", sondern **wie lange soll ein Startfeld +tragen?** Das hängt an `HarvestRateAE` (heute 2 AE/Tick), der Harvesterzahl und +den Baukosten. Rechne es einmal: wie viele Sekunden Spielzeit trägt ein +Startfeld bei einem, bei zwei, bei drei Harvestern? Setze den Wert danach, nicht +davor, und schreib die Rechnung in die PR-Beschreibung. + +> **Vier Spiegel.** Siehe „Risiken" — jede Änderung an der Feldlage geht durch +> alle vier Stellen oder durch keine. + +### 21.4 · Der Baubereich wird sichtbar (#91) + +**Erst nach 21.1**, sonst zeigt das Overlay eine Regel, die sich danach ändert. + +Beim Anklicken des HQ und im Platzierungsmodus wird der erlaubte Bereich +angezeigt. **Nicht als Radius-Ring** — der wäre unehrlich, weil +`MinimumBuildingDistanceCells` Zellen *innerhalb* der Zone sperrt. Einzufärben +sind die **tatsächlich baubaren Zellen** für den gerade gewählten Footprint. +Die Prüfung existiert bereits in `ConstructionSystem`; es geht ausschließlich +darum, die vorhandene Antwort *vor* dem Klick zu zeigen statt danach. + +> Damit beantwortet das Overlay nebenbei die Beschwerde aus 21.1 direkt: der +> Spieler sieht, wie viel Platz noch da ist, statt es zu vermuten. + +**Fertig wenn:** ein Spieler ohne Fehlversuch erkennt, wo das nächste Gebäude +hinpasst — und warum eine Zelle innerhalb des Radius trotzdem gesperrt ist. + +### 21.5 · Die Auswahl sagt die Wahrheit (#88) + +**Abhängigkeitsfrei — jederzeit einzeln machbar.** Der handfeste Teil ist Punkt 3. + +`CommandCardHud.BuildModel` liest heute `selected[0]` und fragt +`GetUnitCommands(faction, leadRole)`. Daraus folgen drei Lücken: + +1. **Keine Typenaufschlüsselung.** „Panzer (+7 weitere)" sagt nicht, ob das + sieben Panzer sind oder ein Harvester und sechs Pioniere. +2. **Kein Zustand.** HP taucht in der Karte nicht auf. +3. **Die Befehle stammen vom Anführer statt von der Schnittmenge.** Steht ein + Harvester zufällig auf Position 0, bietet die Karte „Ernten" an, obwohl es + für die anderen sieben nichts bedeutet — und „Ernten" verschwindet, sobald ein + Panzer die Führung übernimmt, obwohl ein Harvester mitmarkiert ist. Die + angebotenen Befehle hängen an der Reihenfolge der Auswahl. + +Punkt 3 wird zur **Schnittmenge über alle Rollen der Auswahl**. Punkt 1 und 2 +werden zur Aufschlüsselung nach Typ mit Anzahl und Sammel-HP. + +> **Zwei Nachträge pro neuer HUD-Zeile.** `CommandCardHud.EstimateHeight` bildet +> die Höhenrechnung von `OnGUI` Zeile für Zeile nach — der Kommentar dort +> dokumentiert genau diesen Fehler („~40 px short … visible, but not +> clickable"). Und jede neue Trefferfläche gehört in `IsPointerOverHud`, sonst +> schlagen Klicks hinter dem Panel in die Welt durch. + +Alle Daten liegen bereits in `EntityManager`. Kein Simulationseingriff. + +### 21.6 · Die Karte trägt mehr Felder (#93) + +**Erst nach 21.1.** Wie weit eine Basis wachsen darf, bestimmt mit, wie dicht +Felder liegen dürfen. + +Heute: fünf Felder auf 128×128, davon zwei als Startbasis gebunden. Für zwei +Spieler bleiben **drei umkämpfte Felder** — daraus entsteht keine Entscheidung, +sondern ein Wettlauf: jeder nimmt das nächstgelegene freie Feld, die Mitte +entscheidet den Rest. Der Bericht verlangt „mindestens ungefähr doppelt so +viele". + +Kapazitätsseitig ist Luft: `EconomySystem.MaxFields = 64`. Die Zahl ist reine +Kartengestaltung, keine technische Grenze. + +Zu liefern: eine neue Feldlage mit begründeter Anzahl und Verteilung, unter +Wahrung der **bindenden Symmetrie** aus D-107 — Punkte spiegeln als +`(x, y) → (124 - x, 124 - y)`. Asymmetrie ist hier kein Geschmacksfehler, +sondern ein Balancefehler. + +> Die Mitte bleibt in diesem Paket **ein** Feld. Sie wird erst in 21.7 zum Gebiet +> — erst die Gesamtzahl, dann die Verteilung. + +### 21.7 · Die Mitte wird ein Gebiet (#94 → D-109) — **das teuerste Paket** + +**Erst nach 21.6.** Zwei Hälften, und die zweite ist die schwierige. + +**a) Kartenlage.** Vier bis sechs Felder in der Mitte gruppieren, statt des einen +Feldes bei (62, 62) mit 15.000 AE. Symmetrie nach D-107, Gesamtreserve der Zone +begründet gegen die Startfelder. + +**b) Chokepoints — und hier liegt die eigentliche Arbeit.** Schmale Zufahrten +brauchen unbegehbares Gelände. Die Maschinerie existiert (`CostField.ImpassableCost`), +benutzt wird sie nur von `ConstructionSystem`. Zu bauen ist: + +> **Eine einzige autoritative Geländequelle**, aus der *beide* Seiten lesen — +> die Simulation über `CostField.SetCost` und die Optik über +> `GlutrinneBlockoutView`. Genau so, wie die fünf Aetheriumfelder es heute schon +> machen: `MatchBootstrap` hält die kanonische Lage, die Blockout-View baut sich +> daraus. Das Gelände gehört in dieselbe Struktur. +> +> **Das ist die Kernanforderung dieses Pakets.** Zwei getrennte Quellen ergeben +> Einheiten, die durch Felsen laufen und an unsichtbaren Wänden hängenbleiben — +> und das ist ein Fehlerbild, das später niemand mehr der Kartenarbeit zuordnet. + +Zusätzlich zu prüfen und in der PR zu beantworten: + +- Sind die Zufahrten breit genug für die Gruppenbewegung? Ein Chokepoint, durch + den eine Formation nicht passt, ist kein Engpass, sondern eine Blockade. +- Bleibt jedes Feld und jedes HQ von jedem Startpunkt aus erreichbar? Ein + Erreichbarkeitstest über das `FlowField` gehört in + `tools/Nova.SimRunner.Tests/` — sonst sperrt eine spätere Kartenänderung + unbemerkt eine Basis ein. + +**Nicht in diesem Paket:** Verteidigungstürme an den Zufahrten balancieren, und +das Verhalten der KI in der Mitte. Die KI kann heute nicht um ein Gebiet +kämpfen; das ist Sache des Einheitenstrangs und keine Bringschuld dieses Sprints. + +## Bewusst nicht in diesem Sprint + +| Was | Warum | +|---|---| +| **#89 Patrouille, #90 Bewachen** | Beide brauchen einen Eintrag im **eingefrorenen** `CommandKind`-Register (Schema v1, heute 1–17), eine neue Payload und Zustand pro Einheit im Snapshot. Das ist ein API-/Schema-Vorgang: @api-guardian ist Pflicht und die Versionsrelevanz ist eher `major` als `minor`. Wer sie einem Strang still zuschlägt, bricht entweder die Hoheit oder das Schema | +| **KI-Verhalten an den Feldern** | Expansion, Feldsicherung und Eskorten gehören dem Einheitenstrang (13B). Dieser Sprint macht die Karte reicher; sie zu bespielen ist arns Paket | +| **Verteidigungstürme balancieren** | Erst wenn die Mitte steht und einmal gespielt wurde | +| **Doppelte Feldlage auflösen** | Die Verdopplung zwischen `MatchBootstrap` und `Determinism10000Scenario` wäre einen eigenen Aufräum-Issue wert, aber nicht mitten in einer Kartenänderung | + +## Risiken + +**R-1 · Die Feldlage steht viermal literal im Repo.** Verifiziert gegen +`main` @ `3e10c48`: + +``` +Assets/_Project/Scripts/Gameplay/Match/MatchBootstrap.cs:168 +tools/Nova.SimRunner/Determinism10000Scenario.cs:210 +tools/Nova.SimRunner.Tests/CanonicalMatchSetupTests.cs:85 +Assets/Tests/EditMode/Gameplay/CanonicalMatchSetupTests.cs:113 +``` + +Drei von vier ergibt einen roten Test, der wie ein Determinismusfehler aussieht +und keiner ist. Betrifft 21.3, 21.6 und 21.7. + +**R-2 · Verhalten und Baseline nie im selben PR.** Die wichtigste Regel des +Parallelbetriebs. 21.3, 21.6 und 21.7 ändern Simulationsverhalten und lassen +`SnapshotGoldenBytesTests`, `CommandGoldenBytesTests`, `SimRandomGoldenTests` +und `Determinism10000Tests` rot werden. Das ist ihr Zweck. Die Baseline wird in +einem **eigenen** PR neu gesetzt, mit altem und neuem Wert im Text und der +Begründung, warum die Änderung gewollt ist. Das Drehbuch +`Determinism10000Scenario.cs` ist davon **nicht** betroffen und darf im selben +PR nachgezogen werden. + +**R-3 · 21.6 und 21.7 bewegen den gepinnten KI-Ausgang.** Eine andere Karte +heißt eine andere kanonische Partie. `CanonicalAiOutcomeTests` gehört dem +Einheitenstrang. **Vor** dem Merge von 21.6 mit arn abstimmen, in welchem +Merge-Fenster das läuft — „ein Fenster hat einen Strang". Zwei Stränge in einem +Fenster machen einen roten Test nicht zuordenbar. + +**R-4 · Verteilte Testbuilds altern.** Der Fingerprint sperrt Matches zwischen +ungleichen Builds. Nach jedem Fenster: Build für jede Plattform, an der jemand +testet, neuer Build an alle Testenden, alter Build ist ungültig. + +**R-5 · `tools/build/` ist ignoriert.** Der Ordner sieht aus wie der +Packaging-Ordner, ist aber über `.gitignore` ausgeschlossen. Änderungen dort +verschwinden. Der getrackte Weg ist ausschließlich `tools/packaging/`. + +## Fertig wenn + +- [ ] Ein Spieler liest den Restbestand jedes Vorkommens ab, ohne das Debug-HUD + zu öffnen — als Zahl und am Kristallstand auf der Karte (21.2) +- [ ] Der Baubereich ist vor dem Klick sichtbar, inklusive der gesperrten Zellen + innerhalb des Radius (21.4) +- [ ] Die Befehlskarte zeigt bei Mehrfachauswahl Typen, Anzahl und Zustand, und + bietet nur Befehle an, die für **alle** gewählten Einheiten gelten (21.5) +- [ ] Die Startmenge steht auf einem gerechneten Wert, und die Rechnung ist + nachlesbar (21.3) +- [ ] Die Karte trägt genug Felder, dass ein Spieler zwischen Alternativen + wählt statt zu rennen (21.6) +- [ ] Die Mitte ist ein Gebiet mit schmalen Zufahrten, Optik und Begehbarkeit + stammen aus **einer** Quelle, und ein Erreichbarkeitstest sichert, dass + keine Basis eingesperrt ist (21.7) +- [ ] `dotnet test tools/Nova.SimRunner.Tests` grün, Baselines in eigenen PRs + bewegt +- [ ] **Eine gespielte Runde** — dieser Sprint ist überwiegend Oberfläche und + Kartengefühl; die CI kann davon fast nichts belegen + +## Changelog-Notiz + +Je Paket eine Zeile unter `[Unreleased]`. Für 21.6 und 21.7 gehört die alte und +die neue Feldlage in den Eintrag, nicht nur „mehr Felder". + +## Versionsrelevanz + +`minor`. Kein Vertrag bricht: kein neuer `CommandKind`, kein +`StateVersion`-Bump, keine Änderung an `SimDefinitions`. Die Kartenlage bewegt +Determinismus-Baselines, aber keine Schnittstelle. + +> Falls 21.1 zu dem Ergebnis kommt, dass `MinimumBuildingDistanceCells` fällt, +> bewegt das `RulesHash64` — dann ist das ein eigener PR mit eigener D-ID, und +> die Versionsrelevanz dieses Pakets steigt auf die Regelrevision. + +## Änderungsverlauf + +| Version | Datum | Änderung | Autor | +|---|---|---|---| +| 1.0.0 | 2026-08-17 | Erstfassung aus [20_Vorschlag_Verknappungsfolgen.md](20_Vorschlag_Verknappungsfolgen.md) nach den Inhaberentscheidungen D-108 und D-109. #85 als vom Einheitenstrang erledigt ausgetragen, #89/#90 als Vertragsflächen ausgeschlossen | Orchestrator | diff --git a/docs/production/hashkrieg/AUFTRAG_Grossblock.md b/docs/production/hashkrieg/AUFTRAG_Grossblock.md index 486accc..ae18f24 100644 --- a/docs/production/hashkrieg/AUFTRAG_Grossblock.md +++ b/docs/production/hashkrieg/AUFTRAG_Grossblock.md @@ -282,9 +282,18 @@ Es gibt zwei Bedingungen, und **beide** müssen zutreffen: Zwei Dinge, die du dazu wissen musst: -- **Lokal läuft `dotnet test` nicht.** `global.json` pinnt SDK `8.0.318` mit - `rollForward: disable`; auf der Arbeitsmaschine liegt nur `10.0.302`. Der - Nachweis läuft über die CI im PR. Behaupte keinen grünen lokalen Lauf. +- **Lokal läuft `dotnet test` sehr wohl — aber nur mit dem Repo-lokalen SDK.** + *(Berichtigt am 2026-08-17; hier stand vorher das Gegenteil.)* Im Repo-Root + liegt ein mitgeliefertes `.dotnet/` mit exakt der in `global.json` gepinnten + Version `8.0.318`; der vollständige Lauf dauert rund 14 Sekunden: + + ``` + "$PWD/.dotnet/dotnet" test tools/Nova.SimRunner.Tests/Nova.SimRunner.Tests.csproj -c Release + ``` + + Das systemweite `dotnet` (`10.0.302`) scheitert an `rollForward: disable` — + nimm **immer** den Repo-lokalen Pfad. Prüfe lokal, bevor du einen PR + aufmachst, und behaupte weiterhin keinen Lauf, den du nicht gesehen hast. - **Für Block 0, Block 2 und die HUD-Teile von Block 1 führt kein CI-Lauf Gameplay- oder Presentation-Code aus,** und die Unity-EditMode-Tests laufen mangels Lizenz nicht (`505 Unsupported protocol version`). Die Quelltext-Wächter diff --git a/docs/production/hashkrieg/AUFTRAG_Verknappungsfolgen.md b/docs/production/hashkrieg/AUFTRAG_Verknappungsfolgen.md new file mode 100644 index 0000000..99db92d --- /dev/null +++ b/docs/production/hashkrieg/AUFTRAG_Verknappungsfolgen.md @@ -0,0 +1,276 @@ +# Großauftrag: Die Folgen der Verknappung + +**Version:** 1.0.0 | **Status:** verbindlich | **Erteilt:** 2026-08-17 | **Auftraggeber:** Inhaber | **Ausführung:** Kimi (Maintainer-Seite) | **Umfang:** Blöcke 1–2, entspricht Sprint 21 und Sprint 18 | **Grundlage:** `main` @ `3e10c48` | **Leitsatz:** erst sichtbar machen, was die Simulation weiß, dann die Karte anfassen + +## Vorrangregel + +Dieses Dokument ist die **einzige verbindliche Reihenfolge** für die hier +genannten Sprints. Wo es von einer Sprintdatei abweicht, gilt dieses Dokument. +Wo es schweigt, gilt die Sprintdatei. + +Wenn dir etwas widersprüchlich vorkommt: **halte an und frag nach.** Rate nicht. +Ein falsch aufgelöster Widerspruch kostet mehr als eine Rückfrage. + +Der vorige Auftrag [AUFTRAG_Grossblock.md](AUFTRAG_Grossblock.md) ist damit +abgeschlossen, soweit er Code betraf: Block 0 (#49) und Block 1 (Sprint 16, +Pakete 16.1–16.10) liegen auf `main`. Sein Block 3 (Sprint 17 Paket A) bleibt +offen und ist **nicht** Teil dieses Auftrags. + +## Der Auftrag in einem Satz + +Aus dem Betatest T-01 vom 10.08.2026 sind zehn Issues entstanden (#85–#94). Einer +davon (#85) ist bereits vom Einheitenstrang behoben. Du erledigst die übrigen +Befunde des Maintainer-Strangs und ziehst den lange geplanten Sprint 18 direkt +hinterher, weil beide dieselben zwei Dateien anfassen — Befehlskarte und +Auswahl. + +## Warum diese Reihenfolge + +Der Bericht sagt es selbst: die endlichen Felder aus #80 waren kein Wert, +sondern ein Systemwechsel. Acht Systeme stehen noch auf der alten Annahme. Zwei +davon sind **unsichtbar geworden** statt falsch — der Restbestand und der +Baubereich existieren exakt und kommen nirgends an. Die macht dieser Auftrag +zuerst sichtbar, weil danach über Zahlen balanciert wird statt über Gefühl. + +Der Beleg dafür steht im Bericht: der Tester schätzte das Startvorkommen auf +5.000 AE, tatsächlich sind es 9.000. Die Fehleinschätzung um fast die Hälfte ist +kein Vorwurf an ihn, sondern die Messgröße für das Problem. + +## Was du nie anfasst + +Diese Pfade gehören dem **externen Beitragenden** (Einheitenstrang 13B). Ein PR, +der sie berührt, wird nicht gemergt, sondern zurückgegeben: + +``` +Assets/_Project/Scripts/Simulation/Combat/ +Assets/_Project/Scripts/Simulation/Movement/ +Assets/_Project/Scripts/Simulation/Factions/ +Assets/_Project/Scripts/Simulation/Pathfinding/ +Assets/_Project/Scripts/AI/ +Assets/_Project/Scripts/AI.Data/ +Assets/_Project/Scripts/Presentation/UI/DebugHud.cs +tools/Nova.AiLab/ tools/Nova.AiLab.Tests/ +tools/Nova.SimRunner.Tests/CanonicalAiOutcomeTests.cs +tools/Nova.SimRunner.Tests/SkirmishAi*.cs +``` + +> **Die eine Ausnahme, die du brauchst und die keine ist:** Block 1 Paket 21.7 +> schreibt Gelände über die **bestehende öffentliche** `CostField.SetCost` aus +> `Gameplay/Match/` — genauso, wie `PathfindingTestBootstrap` es heute schon +> tut. Du fasst `Simulation/Pathfinding/` dabei **nicht** an. Die Hoheit bleibt +> gewahrt. + +Diese sind **eingefroren** und brauchen eine Inhaberentscheidung mit D-ID: + +``` +Assets/_Project/Scripts/Simulation/CommandsV1/ ← kein neuer CommandKind +Assets/_Project/Scripts/Simulation/Replays/ +Assets/_Project/Scripts/Simulation/Snapshots/ +Assets/_Project/Scripts/Simulation/Systems/ +Assets/_Project/Scripts/Simulation/SimulationKernel.cs +Assets/_Project/Scripts/Simulation/State/ — nur Layout und Serialisierung +``` + +`Simulation/State/UnitCommandStateView.cs` darfst du bearbeiten, aber nur die +Befehlsanwendung — *was* ein bestehender `CommandKind` mit dem Zustand tut +(D-095). Kein neues Feld, keine neue Reihenfolge, kein `StateVersion`-Bump. + +Und diese vier Dateien fasst **kein Verhaltens-PR** an: + +``` +tools/Nova.SimRunner.Tests/SnapshotGoldenBytesTests.cs +tools/Nova.SimRunner.Tests/CommandGoldenBytesTests.cs +tools/Nova.SimRunner.Tests/SimRandomGoldenTests.cs +tools/Nova.SimRunner.Tests/Determinism10000Tests.cs +``` + +Ausnahme: ein **eigener** PR, der ausschließlich eine Baseline neu setzt, mit +altem und neuem Wert im Text und der Begründung. Nie zusammen mit einer +Verhaltensänderung. Das Drehbuch `tools/Nova.SimRunner/Determinism10000Scenario.cs` +ist davon **nicht** betroffen und darf im selben PR nachgezogen werden. + +## Die zwei Blöcke + +Arbeite sie **in dieser Reihenfolge** ab. Zwischen den Blöcken liegt ein Gate: +erst wenn der vorige gemergt und gespielt gesehen ist, fängt der nächste an. + +### Block 1 · Sprint 21 — Die Verknappung wird lesbar und bespielbar + +**Binde Sprintdatei:** [21_Sprint_Verknappungsfolgen.md](21_Sprint_Verknappungsfolgen.md) + +Sieben Pakete, 21.1 bis 21.7, in der dort stehenden Reihenfolge. Sie ist nach +Abhängigkeit sortiert, nicht nach Aufwand: + +| | Paket | Issue | Hängt an | +|---|---|---|---| +| 21.1 | Territoriumsregel aussprechen und Enge messen | #92 → D-108 | — | +| 21.2 | **Restbestand sichtbar machen** (kritisch) | #86 | — | +| 21.3 | Startmenge rechnen statt raten | #87 | 21.2 | +| 21.4 | Baubereich sichtbar machen | #91 | 21.1 | +| 21.5 | Auswahl sagt die Wahrheit | #88 | — | +| 21.6 | Karte trägt mehr Felder | #93 | 21.1 | +| 21.7 | **Die Mitte wird ein Gebiet** (teuerstes) | #94 → D-109 | 21.6 | + +**21.5 ist abhängigkeitsfrei.** Zieh es vor, wenn du an einer Stelle wartest. + +**Die Abwurfliste, falls die Zeit nicht reicht:** erst 21.7, dann 21.6, dann +21.3. **21.1, 21.2, 21.4 und 21.5 fallen nicht** — sie sind der Grund, warum +dieser Sprint existiert. Was fällt, kommt mit Begründung in den +[ScopeLedger](../ScopeLedger.md). + +**Zwei Dinge, die du aus der Sprintdatei allein nicht siehst:** + +- **21.6 und 21.7 bewegen den gepinnten Ausgang der kanonischen KI-Partie.** Eine + andere Karte heißt eine andere Partie. `CanonicalAiOutcomeTests` gehört dem + Einheitenstrang. Beide Pakete brauchen ein eigenes Merge-Fenster, abgestimmt + mit @arn-c0de — „ein Fenster hat einen Strang". Sag Bescheid, bevor du 21.6 + aufmachst, statt danach. +- **21.2 legt kein Feld in den Zustand.** Die Anzeige „6.420 / 9.000" braucht die + Anfangsreserve. Sie kommt aus der kanonischen Kartenlage, **nicht** aus einem + neuen Feld in `AetheriumField` — das wäre `Simulation/State/`-Layout und damit + eingefroren. + +### Block 2 · Sprint 18 — Befehl und Auswahl werden lesbar + +**Binde Sprintdatei:** [18_Sprint_Befehl_und_Auswahl.md](18_Sprint_Befehl_und_Auswahl.md) + +Drei Pakete, die Issues #50, #51 und #52. Fasst **keine** Simulationsdatei an +außer der Zielverteilung in `ApplyMove`. 18.3 (Formationsausrichtung) ist die +erste Abwurfkandidatin — die Verteilung selbst existiert seit Sprint 11 bereits. + +**Warum dieser Block direkt hinter Sprint 21 kommt und nicht davor:** 21.5 (#88) +und 18.1 (#50) fassen beide `CommandCardHud` und `SelectionManager` an, aus +entgegengesetzten Richtungen — 21.5 *liest* eine bestehende Auswahl, 18.1 +*stellt* eine her. Sie hintereinander zu bauen spart eine Runde Konfliktauflösung +in genau den zwei Dateien, die dieser Auftrag am häufigsten öffnet. + +## Die fünf stillen Fallen + +Diese brechen nichts sofort. Sie brechen später, an einer Stelle, die nicht nach +der Ursache aussieht. + +**1 · Die Feldlage steht viermal literal im Repo.** Verifiziert gegen `3e10c48`: + +``` +Assets/_Project/Scripts/Gameplay/Match/MatchBootstrap.cs:168 +tools/Nova.SimRunner/Determinism10000Scenario.cs:210 +tools/Nova.SimRunner.Tests/CanonicalMatchSetupTests.cs:85 +Assets/Tests/EditMode/Gameplay/CanonicalMatchSetupTests.cs:113 +``` + +Drei von vier ergibt einen roten Test, der wie ein Determinismusfehler aussieht +und keiner ist. Betrifft 21.3, 21.6 und 21.7. + +**2 · Die Symmetrie ist bindend, nicht kosmetisch.** D-107: Punkte spiegeln als +`(x, y) → (124 - x, 124 - y)`, der Ursprung eines 3×3-Footprints als +`(x, y) → (122 - x, 122 - y)`. Eine asymmetrische Feldlage ist kein +Geschmacksfehler, sondern ein Balancefehler, den niemand als solchen meldet — er +sieht aus wie „die KI ist zu stark". + +**3 · Gelände hat heute genau eine Quelle zu viel.** `CostField` kann +unbegehbare Zellen (`ImpassableCost = 255`), aber es schreibt niemand hinein +außer `ConstructionSystem`. Und `GlutrinneBlockoutView` streut ~84 Felsen, die +laut eigener Zusicherung *„never writes into simulation state"* — sie sind +**Deko und begehbar**. Wer in 21.7 Chokepoints baut und beide Seiten getrennt +speist, bekommt Einheiten, die durch Felsen laufen und an unsichtbaren Wänden +hängenbleiben. Optik und Begehbarkeit müssen aus **derselben** Struktur stammen, +so wie die fünf Aetheriumfelder es heute schon tun. + +**4 · Jede neue HUD-Zeile braucht zwei Nachträge.** `CommandCardHud.EstimateHeight` +bildet die Höhenrechnung von `OnGUI` Zeile für Zeile nach — der Kommentar dort +dokumentiert genau diesen Fehler aus der Vergangenheit („~40 px short … visible, +but not clickable"). Und jede neue Trefferfläche gehört in `IsPointerOverHud`, +das heute drei Komponenten kennt; fehlt sie, schlagen Klicks hinter dem Panel in +die Welt durch. Betrifft 21.2, 21.5 und den ganzen Block 2. + +**5 · `tools/build/` ist ignoriert.** Der Ordner sieht aus wie der +Packaging-Ordner und enthält eine fast identische Kopie von `build-mac.sh`, ist +aber über `.gitignore` ausgeschlossen. Änderungen dort verschwinden. Der +getrackte Weg ist ausschließlich `tools/packaging/`. + +## Wie du arbeitest + +| | | +|---|---| +| **Branch** | eigener Topic-Branch je Paket (`feat/`, `fix/`), `main` ist PR-only | +| **PR-Schnitt** | ein PR je Paket. Lieber mehrere kleine als einer, der drei Ordner öffnet | +| **Verhalten und Baseline** | nie im selben PR. Baseline-Neusetzung ist ein eigener PR mit altem und neuem Wert im Text | +| **CHANGELOG** | genau eine Zeile unter `[Unreleased]`, ganz oben im Abschnitt. Keine datierte Versionsüberschrift anlegen | +| **Commit** | Conventional Commit | +| **Push** | **nie ohne ausdrückliche Freigabe des Inhabers** | +| **Deploy** | nie. Weder VPS noch Supabase | + +### Der Nachweis + +Zwei Bedingungen, und **beide** müssen zutreffen: + +1. `dotnet test tools/Nova.SimRunner.Tests` ist grün — bei einem + verhaltensändernden PR **nach** dem unmittelbar folgenden Baseline-PR. Ein + roter Golden-Byte-Test im Verhaltens-PR ist dort erwartet und kein Blocker. +2. Ein Mensch hat die Sache im laufenden Spiel gesehen und es notiert — im PR + oder im [GrayboxLog](../GrayboxLog.md). + +> **Berichtigung gegenüber [AUFTRAG_Grossblock.md](AUFTRAG_Grossblock.md):** +> dort steht, lokal laufe `dotnet test` nicht. **Das stimmt nicht (mehr).** Im +> Repo-Root liegt ein mitgeliefertes `.dotnet/` mit exakt der in `global.json` +> gepinnten Version `8.0.318`. Der vollständige Lauf dauert rund 14 Sekunden: +> +> ``` +> "$PWD/.dotnet/dotnet" test tools/Nova.SimRunner.Tests/Nova.SimRunner.Tests.csproj -c Release +> ``` +> +> Das systemweite `dotnet` scheitert an `rollForward: disable` — nimm **immer** +> den Repo-lokalen Pfad. Du kannst und sollst also lokal prüfen, bevor du einen +> PR aufmachst. + +Was die CI trotzdem nicht leistet: `Nova.SimRunner.Tests` linkt nur Core, +Simulation, AI, AI.Data und Networking. **Für alles in `Gameplay/` und +`Presentation/` führt kein CI-Lauf den Code aus**, und die Unity-EditMode-Tests +laufen mangels Lizenz nicht. Das betrifft in diesem Auftrag den größten Teil von +21.2, 21.4, 21.5 und den ganzen Block 2. Die Quelltext-Wächter greifen dort +trotzdem: `PresentationSourceBoundaryTests` scannt auf `GetUnitRef(` und +`.Random`, ebenso der asmdef-Rangcheck. Ein *Verhaltens*nachweis ist dort die +gespielte Runde plus Screenshot. Schreib in den PR, was du gesehen hast — und +wenn du es nicht selbst sehen kannst, sag das, statt es zu behaupten. + +### Was du selbst entscheidest + +Alles Handwerkliche: Benennung, Aufteilung, Reihenfolge innerhalb eines Pakets, +Konstanten ohne Designwirkung, die konkrete Optik eines Overlays. Notier die +Entscheidung kurz im PR. + +### Was du nicht entscheidest + +- Einen neuen `CommandKind` einführen +- `StateVersion`, Schemaversionen oder das Zustandslayout ändern — auch nicht + „nur ein Feld" in `AetheriumField` +- Die Tickreihenfolge in `MatchRunner` ändern oder ein neues System registrieren +- Die Anzahl oder Lage der Aetheriumfelder ohne die Symmetrieprüfung aus D-107 +- `MinimumBuildingDistanceCells` oder `BuildInfluenceRadiusCells` ändern, bevor + die Messung aus 21.1 vorliegt +- Ein Paket streichen, das nicht auf der Abwurfliste steht +- Irgendetwas in fremdem Terrain, auch wenn es „nur eine Zeile" wäre + +In allen Fällen: anhalten, im PR oder in einer Nachricht beschreiben, warum es +nötig wäre, und auf die Entscheidung warten. + +## Was nicht in diesem Auftrag ist + +| | Warum | +|---|---| +| **#89 Patrouille, #90 Bewachen** | Brauchen einen Eintrag im eingefrorenen `CommandKind`-Register, eine neue Payload und Zustand pro Einheit im Snapshot. API-/Schema-Vorgang mit @api-guardian, Versionsrelevanz eher `major` | +| **#85 KI erntet auf leerem Feld** | Bereits behoben, [PR #97](https://github.com/VibecodingGermany/HashKrieg/pull/97), Einheitenstrang | +| **KI-Verhalten an den neuen Feldern** | Expansion, Feldsicherung, Eskorten — Einheitenstrang 13B. Dieser Auftrag macht die Karte reicher, nicht die KI klüger | +| **Sprint 17 Paket A** (Zugangsprotokoll) | Offen aus dem vorigen Auftrag, eigener Block nach diesem | +| **Sprint 13.2, 13.4, 13.5** | 13.2 braucht Zugangsdaten, 13.4/13.5 brauchen zwei Menschen an zwei Rechnern. Kein Codeauftrag | +| **Sprint 15.1–15.4** | Eigener Sprint, nach diesem Auftrag | +| **Sprint 19 / Art** (#57, #58) | Art-Arbeit außerhalb des Repositories | +| **#42 Zittern im Pulk, #66/#67 Halte-Feuer und Strommangel in der Verteidigung** | `Simulation/Movement/` und `Simulation/Combat/` — Einheitenstrang | +| **#55 Reparaturzone, #56 Sanitäter** | Im Fragenkatalog, kein Bauauftrag | +| **Verteidigungstürme an den Chokepoints balancieren** | Erst wenn die Mitte steht und einmal gespielt wurde | + +## Änderungsverlauf + +| Version | Datum | Änderung | Autor | +|---|---|---|---| +| 1.0.0 | 2026-08-17 | Erstfassung: Sprint 21 und Sprint 18 gebündelt, gegen `main` @ `3e10c48` geprüft, Grenzen und stille Fallen benannt. Enthält die Berichtigung zur lokalen Testbarkeit gegenüber dem vorigen Auftrag | Orchestrator | diff --git a/docs/production/hashkrieg/README.md b/docs/production/hashkrieg/README.md index b3a340d..53169bd 100644 --- a/docs/production/hashkrieg/README.md +++ b/docs/production/hashkrieg/README.md @@ -1,6 +1,6 @@ # Übergang Project Nova → Hashkrieg — Planungsmappe -**Version:** 0.8.0 | **Status:** fortgeschriebene Planungsmappe – Sprint 16 technisch umgesetzt, manuelle Spielabnahme offen; Sprint 13.2–13.5 warten weiter auf Zugangsdaten und zwei Menschen an zwei Rechnern | **Verantwortungsbereich:** Project Owner / Orchestrator / Producer | **Sprint:** 16 +**Version:** 0.9.0 | **Status:** fortgeschriebene Planungsmappe – Sprint 16 technisch umgesetzt und Sprint 21 festgeplant, manuelle Spielabnahme beider offen; Sprint 13.2–13.5 warten weiter auf Zugangsdaten und zwei Menschen an zwei Rechnern | **Verantwortungsbereich:** Project Owner / Orchestrator / Producer | **Sprint:** 21 ## Zweck @@ -51,9 +51,12 @@ ausschließlich in [../MVPRecoveryPlan.md](../MVPRecoveryPlan.md) und | [15_Sprint_Netzstabilitaet.md](15_Sprint_Netzstabilitaet.md) | Sprint 15 (Maintainer); Reconnect, Desync-Erstbefund, adaptive Eingabeverzögerung, Dauerbetrieb des Relays | | [16-19_Betatest_Einordnung.md](16-19_Betatest_Einordnung.md) | **Einordnung des ersten Betatest-Berichts** in die Sprintfolge — Issues #43–#58, nach Schreibhoheit geschnitten, mit den offenen Inhaberentscheidungen | | [16_Sprint_Wirtschaft.md](16_Sprint_Wirtschaft.md) | Sprint 16 (Netzstrang, **technisch umgesetzt; manuelle Spielabnahme offen**); Strang C aus Sprint 12 und die **acht** Betatest-Befunde (#43, #44, #45, #46, #47, #48, #53, #54) — Knappheit, Lager, Radar, Low Power, Bauvoraussetzungen, Platzierung, Reparaturkosten und Entscheidungsfeedback | -| [17_Sprint_Zugangsprotokoll.md](17_Sprint_Zugangsprotokoll.md) | Sprint 17 (Maintainer); Zugriffsprotokoll, Sperrliste und Erstmeldung — Paket A läuft im Großauftrag als **Block 4 hinter der Lobby**, weil es die Lobby-Functions aus Sprint 14 voraussetzt; es liegt bis auf den `.partial`-Fix in `RelayServerCore.cs` ausserhalb des Repos | +| [17_Sprint_Zugangsprotokoll.md](17_Sprint_Zugangsprotokoll.md) | Sprint 17 (Maintainer); Zugriffsprotokoll, Sperrliste und Erstmeldung — Paket A war **Block 3** des vorigen Großauftrags und ist als einziger Block daraus **noch offen**; es setzt die Lobby-Functions aus Sprint 14 voraus und liegt bis auf den `.partial`-Fix in `RelayServerCore.cs` ausserhalb des Repos | | [18_Sprint_Befehl_und_Auswahl.md](18_Sprint_Befehl_und_Auswahl.md) | Sprint 18 (Netzstrang); Auswahl nach Rolle, sichtbares Angriffsziel mit Nachsetzen über zwei Intents, Formationsausrichtung — Eingabe und Darstellung, kein neuer `CommandKind` | -| [AUFTRAG_Grossblock.md](AUFTRAG_Grossblock.md) | **Der gebündelte Arbeitsauftrag an den ausführenden Agenten, Blöcke 0 bis 4** — Auswahlrahmen, Sprint 16, Sprint 18, Sprint 14, Sprint 17 Paket A. Er ist die verbindliche Reihenfolge; wo er von einer Sprintdatei abweicht, gilt er | +| [20_Vorschlag_Verknappungsfolgen.md](20_Vorschlag_Verknappungsfolgen.md) | Der Vorschlag zur Sprintbildung aus Testbericht T-01 (#85–#94), nach Schreibhoheit geschnitten — **historisch**, seit dem 2026-08-17 durch Sprint 21 festgeplant | +| [21_Sprint_Verknappungsfolgen.md](21_Sprint_Verknappungsfolgen.md) | **Sprint 21 (Maintainer-Strang, geplant); die Folgen der endlichen Felder** — Restbestand und Baubereich sichtbar machen, Auswahl ehrlich machen, Startmenge rechnen, Kartendichte, und die Mitte als Gebiet mit Chokepoints (#86–#88, #91–#94; D-108, D-109) | +| [AUFTRAG_Grossblock.md](AUFTRAG_Grossblock.md) | Der vorige Arbeitsauftrag, Blöcke 0 bis 3 — Auswahlrahmen, Sprint 16, Sprint 18, Sprint 17 Paket A. Codeseitig **abgeschlossen bis auf Block 3** (Sprint 17 Paket A) | +| [AUFTRAG_Verknappungsfolgen.md](AUFTRAG_Verknappungsfolgen.md) | **Der aktuelle gebündelte Arbeitsauftrag, Blöcke 1 bis 2** — Sprint 21 und danach Sprint 18. Er ist die verbindliche Reihenfolge; wo er von einer Sprintdatei abweicht, gilt er | | [Testberichte/](Testberichte/) | **Anonymisierte** Fassungen der eingegangenen Betatest-Berichte, je Build und Kennung — Ablauf: [../Nutzerfeedback_Ablauf.md](../Nutzerfeedback_Ablauf.md) | ## Das Wichtigste in fünf Sätzen @@ -67,9 +70,11 @@ ausschließlich in [../MVPRecoveryPlan.md](../MVPRecoveryPlan.md) und einzige echte Blockade zwischen „Sandkasten" und „Spiel" — galt bis zum 2026-08-06 und ist seitdem überholt. Was heute im Weg steht, steht in den Betatest-Befunden, nicht in der Systemregistrierung. -3. **Zwei Gebäude sind Attrappen.** Lager und Radar kosten Geld und Strom und - tun nichts. Das ist die zutreffende Fassung der Vermutung „pro Fraktion - fehlen zwei Gebäude". +3. ~~**Zwei Gebäude sind Attrappen.**~~ **Erledigt seit Sprint 16.** Lager und + Radar kosteten Geld und Strom und taten nichts — das war die zutreffende + Fassung der Vermutung „pro Fraktion fehlen zwei Gebäude". Seit den Paketen + 16.4 (#53, abgeleitete AE-Obergrenze) und 16.5 (#54, Radarabdeckung schaltet + die Minimap frei) wirken beide. 4. **Die halbe fertige Arbeit ist unerreichbar.** Alle 17 Legion-Definitionen und -Assets sind fertig, aber es gibt keine Fraktionswahl — der Mensch kann nur Allianz spielen. @@ -182,29 +187,37 @@ Masterplans grundlegend — sonst nichts. zum Server. 13.4 und 13.5 brauchen zwei Menschen an zwei Rechnern. Sie warten auf den Inhaber, nicht auf Arbeitskraft — und sie halten deshalb nichts auf, was daneben laufen kann. -3. **Als nächstes läuft der Großauftrag** - ([AUFTRAG_Grossblock.md](AUFTRAG_Grossblock.md)), fünf Blöcke am Stück: - - **Block 0 — Auswahlrahmen** (#49): eine Konstante in - `GroundMarkerVisuals.cs`, Wirkung sofort sichtbar. - - **Block 1 — [Sprint 16](16_Sprint_Wirtschaft.md): technisch umgesetzt.** - Die Wirtschaft trägt sich selbst; die manuelle Spielabnahme bleibt offen. +3. **Der vorige Großauftrag** ([AUFTRAG_Grossblock.md](AUFTRAG_Grossblock.md)) + ist codeseitig abgearbeitet: Block 0 (Auswahlrahmen, #49) und Block 1 + ([Sprint 16](16_Sprint_Wirtschaft.md), Pakete 16.1–16.10) liegen auf `main`, + Sprint 14 war bereits gebaut. **Offen bleibt allein sein Block 3** — + [Sprint 17](17_Sprint_Zugangsprotokoll.md) Paket A samt dem `.partial`-Leck + in `Assets/_Project/Scripts/Networking/RelayServerCore.cs`: `ResetMatch` + verwirft den Aufzeichnungsstrom und merkt sich den Pfad, löscht die Datei + aber nie. Paket B wartet weiterhin auf Sprint 15. +4. **Als nächstes läuft der Großauftrag Verknappungsfolgen** + ([AUFTRAG_Verknappungsfolgen.md](AUFTRAG_Verknappungsfolgen.md)), zwei Blöcke + am Stück: + - **Block 1 — [Sprint 21](21_Sprint_Verknappungsfolgen.md):** die Folgen der + endlichen Felder aus Testbericht T-01. Restbestand und Baubereich sichtbar, + Auswahl ehrlich, Startmenge gerechnet, mehr Felder auf der Karte, und die + Mitte wird ein Gebiet mit Chokepoints (D-108, D-109). - **Block 2 — [Sprint 18](18_Sprint_Befehl_und_Auswahl.md):** Befehl und - Auswahl werden lesbar. - - **Block 3 — [Sprint 14](14_Sprint_Lobby.md):** Match per Code über - Supabase, Fraktionswahl, Build-Abgleich. - - **Block 4 — [Sprint 17](17_Sprint_Zugangsprotokoll.md) Paket A:** liegt bis - Es läuft als **Block 3 des Großauftrags**, weil es die Lobby-Functions - aus Sprint 14 voraussetzt — die seit `b4e75e5` auf `main` liegen. - `.partial`-Leck in `Assets/_Project/Scripts/Networking/RelayServerCore.cs`. - `ResetMatch` verwirft den Aufzeichnungsstrom und merkt sich den Pfad, - löscht die Datei aber nie. Paket B wartet weiterhin auf Sprint 15. -4. **Die `SimDefinitions`-Pakete wurden vor dem VPS-Rollout integriert.** + Auswahl werden lesbar. Direkt hinter Sprint 21, weil beide dieselben zwei + Dateien anfassen — Befehlskarte und Auswahl. +5. **Der Einheitenstrang läuft parallel und ist eingeholt.** Die KI erntet seit + [#97](https://github.com/VibecodingGermany/HashKrieg/pull/97) nicht mehr + endlos auf dem leeren Feld (#85 geschlossen), und + [#96](https://github.com/VibecodingGermany/HashKrieg/pull/96) hat den + Goal-Katalog samt `DefendHome` gebracht (`r8`). Beides ist gemergt, aber + **nicht gespielt abgenommen**. +6. **Die `SimDefinitions`-Pakete wurden vor dem VPS-Rollout integriert.** Sprint 16.7 (Feldwerte und Feldanzahl) und 16.8 (Bauvoraussetzungs-Bitmaske) sind abgeschlossen. Der Relay vergleicht den Definitions-Hash **serverseitig**; spätere Zahlenänderungen kosten deshalb Serverzugang und Redeploy ([13-15_Parallelbetrieb.md](13-15_Parallelbetrieb.md), §Definitions-Hash). -5. **Sprint 19 bleibt danach und ist kein Codeauftrag.** Die beiden Art-Befunde +7. **Sprint 19 bleibt danach und ist kein Codeauftrag.** Die beiden Art-Befunde #57 (Gebäude durchsichtig und hohl) und #58 (Maßstab des Radarturms) sind Arbeit am Asset; #58 hängt zusätzlich an der offenen Frage #19. Sprint 16 Paket 16.2 macht #57 sichtbarer, behebt es aber ausdrücklich nicht. @@ -219,4 +232,5 @@ Masterplans grundlegend — sonst nichts. | 0.7.0 | 2026-08-09 | Nach der Inhaberentscheidung zum ersten Betatest: **Sprint 16 vorgezogen**, [16_Sprint_Wirtschaft.md](16_Sprint_Wirtschaft.md) und [18_Sprint_Befehl_und_Auswahl.md](18_Sprint_Befehl_und_Auswahl.md) in die Mappe aufgenommen, Regelwerk als Parallelbetrieb 13–18 mit Trennung über Dateihoheit (**D-095**) fortgeschrieben, Großauftrag mit den Blöcken 0 bis 4 eingehängt. „Nächste Schritte" neu geschrieben: Sprint 13 halb gemergt (`e15f5e6`), 13.2–13.5 nicht durch einen Agenten erledigbar, `SimDefinitions`-Pakete vor dem VPS-Rollout. Punkt 2 der Fünf-Sätze-Zusammenfassung nach **D-077** berichtigt — die Skirmish-KI ist registriert und spielt | Orchestrator | | 0.7.1 | 2026-08-09 | Index gegen den Großauftrag und die Sprintdateien nachgezogen: Sprint 17 Paket A ist nicht „sofort vorziehbar", sondern läuft als **Block 3 hinter der Lobby**, die seit `b4e75e5` auf `main` gebaut ist, und es berührt mit dem `.partial`-Fix in `RelayServerCore.cs` genau **eine** Datei unter `Assets/`. Sprint 16 trägt **acht** Betatest-Befunde (#43, #44, #45, #46, #47, #48, #53, #54), nicht sechs. Alle Markdown-Links dieser Datei gegen das Dateisystem geprüft — kein toter Link | Orchestrator | | 0.7.2 | 2026-08-10 | D-105 nachgezogen: alleinige Projektleitung, sichtbare Spielabnahme-Zurückstellung und den historischen Charakter des D-091-Zwei-Maintainer-Rollouts im Index kenntlich gemacht | Project Owner / Orchestrator | +| 0.9.0 | 2026-08-17 | Sprint 21 aus dem Vorschlag zu den Verknappungsfolgen festgeplant und der [Großauftrag Verknappungsfolgen](AUFTRAG_Verknappungsfolgen.md) (Sprint 21 → Sprint 18) eingehängt; **D-108** (Territorium wächst kriechend an jedem Bauanker) und **D-109** (die Mitte wird ein Gebiet mit Chokepoints, Begehbarkeit und Optik aus einer Quelle) getroffen. „Nächste Schritte" neu geschrieben: der vorige Großauftrag ist codeseitig bis auf Sprint 17 Paket A abgearbeitet, der Einheitenstrang ist mit #96 und #97 eingeholt. #85 geschlossen | Project Owner / Orchestrator | | 0.8.0 | 2026-08-10 | Sprint 16 als technisch umgesetzt markiert, Paket 16.10 und die vor dem VPS-Rollout integrierten Definitionsänderungen nachgezogen; manuelle Spielabnahme bleibt ausdrücklich offen | Codex / Dennis Westermann |