Figur und Lanze getrennt von Meshy; build_figure legt die Lanze in die
rechte Hand und bindet sie an RightHand (props), Lanzenstoß aus dem Stand
(in_place). Ersetzungen gelten nach den Godot-Zuordnungen. HUD-Porträts
zeichnen Skelettfiguren als gebackenes Netz: mit GPU-Skinning blieben
Karten leer. 110 Credits. Stresstest 38 Funkenlanzen gegen Phase 18:
Mid 128,6 -> 147,6 fps, Karte 112,4 -> 128,0. Tests grün, Fingerabdrücke
unverändert.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Konzept aus Icon, Phase-4-Modell und Kohlenbeißer-Konzept als Stilvorlage,
Modell, Skelett und sieben Bibliotheks-Clips für 68 Credits; Figurendatei
vom Kohlenbeißer übernommen, Lane-Fassung inklusive. Bildwerkzeug und
Stresstest nehmen aufgewertete Truppen. Stresstest 35 Schlackenklauen:
Mid 152,5 -> 135,8 fps, Karte 116,7 -> 115,6. Tests grün, Fingerabdrücke
unverändert.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pilot für eine generierte Figur: der Kohlenbeißer g01 kommt als Meshy-Ergebnis
in den Port und ersetzt dort das Phase-4-Modell. Eine Figur genügt, um Pipeline,
Bild und Leistung zu bewerten; Anatomie, Gesichter und Haare bleiben
Künstler-Sculpts oder lizenzierte Packs (Vorgabe vom 1. Oktober).
- Meshy-Pipeline unter tools/meshy/: API-Client (meshy.py, Ledger, Schlüssel
nie geloggt) und Blender-Generator (build_figure.py) aus den unveränderten
Downloads in assets-source/meshy/g01/. Export über den Manifest-Eintrag
kohlenbeisser mit "replaces": "g01"; LuneUnitLibraryBuilder hängt die Figur
zusätzlich unter der Godot-ID ein.
- UV-Material AI_Kohlenbeisser (Familie authored): die Karten der Figur selbst,
Lava-Glut aus der Albedo-Alpha (Meshy 7.1 ohne Emission-Map) mit _Glow 1,25.
- Schatten ohne Normalen-Versatz (LuneShadowBias, _ShadowNormalScale 0): die
UV-Naht-Kopien tragen geknickte Normalen; URP ApplyShadowBias zog helle
Nähte durch den Schatten. Die Figur wirft nur mit Tiefen-Bias.
- GPU-Batched-Skinning (PlayerSettings.meshDeformation, LuneProjectSetup):
35 Meshy-Kohlenbeißer kosteten mit CPU-Skinning rund 1 ms Haupt- und
1,7 ms Render-Thread je Bild.
- LuneBenchmark: -luneBenchmarkRound und -luneBenchmarkArmy (Figuren-Stress).
LuneAssetPreview: LUNE_ONLY für Vorher/Nachher, Trefferframe aus der
Kontaktzeit des Manifests. FigureViewsTests (Explicit) für die vier
Spielmomente der Figur.
- Tests: EditMode 29/29, PlayMode 14/14 (6 Explicit), Verify 718/0,
Player-Selbsttest 30/30, Kerntests 457/457, Fingerabdrücke unverändert
(DCE95C96556F3A1A, 7B8E43AEFC0D60C5).
- Leistung (A/B im selben Fenster, 35x g01): Meshy -21 % Mid (109,7 zu 138,8)
und -13 % Karte (91,7 zu 105,6) gegenüber Phase-4. GPU-Skinning hebt Mid
um 7-27 % und entlastet Haupt- und Render-Thread. Standard-Partie ab Runde 21
ohne g01 im Bild: drei Varianten bis 6 %.
- Doku: U5-VISUAL (U5.5), PORT-QA, PORT-STATUS, KNOWN-BEHAVIOR-DIFFERENCES;
Bilder screenshots/u5.5/ und u5.5-gpu/, Rohdaten logs/u5.5/.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Die Figuren (Einheiten, Monster, Völker, Helden) bekommen den Materialweg
der Welt; dazu Umgebungsverdeckung für die ganze Szene.
- Surface-Materialien für alle 146 Figurenmaterialien (142 neu unter
Materials/Units/, die LN_Boss_* gehörten schon zu den Gebäuden). Farbe,
Rauigkeit und Emission bleiben die Blender-Werte; Metalle werden
metallisch (vorher war keines der 414 Figurenmaterialien metallisch),
ein Randlicht hebt die Silhouetten im Draufblick vom Boden ab.
- Oberflächenstruktur je Materialfamilie im eigenen Raum der Figur, nur
in den HUD-Porträts. Im Feld (30-60 px hohe Figuren) war sie nicht zu
sehen und kostete rund 10 % Bildrate.
- Ringborkes 4k-Satz liegt am Schnittholz (RB_Cutwood), wohin er gehört;
U5.3 hatte ihn an die Rinde gebunden. Verwaistes RB_Bark.mat entfernt.
- SSAO über LuneProjectSetup: nach den opaken Objekten, halbe Auflösung,
Radius 0,35 m, Ausblendung ab 260 m. Standardmäßig an (Entscheidung des
Projektinhabers), in den Optionen abschaltbar, -luneSsao 0 für eine
Sitzung. Die Variante mit Tiefen-Normalen-Vorpass kostete 19-28 %.
- Shader: Steinreliefkarte nur noch für Gelände, Stein, Pflaster, Erde.
- Werkzeug: Übersichtsbilder mit LUNE_DRESS=1 eingekleidet wie im Spiel;
das Materialset wird nach der leeren Vorschauszene geladen (sie entlädt
unreferenzierte Assets).
- Tests: EditMode 29/29, PlayMode 14/14, Verify 718/0, Player-Selbsttest
30/30 (4 neue zur SSAO-Option), Fingerabdrücke unverändert
(DCE95C96556F3A1A, 7B8E43AEFC0D60C5).
- Leistung (A/B mit U5.3 im selben Lauf): Mid nah 177,7 -> 148,5 fps
(-16 %), Karte 127,8 -> 111,5 fps (-13 %); ohne SSAO -3,5 / -4,5 %.
- Doku: U5-VISUAL (U5.4), PORT-STATUS, PORT-QA; Bilder screenshots/u5.4/.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PORT-QA, U4-NETWORK und PORT-STATUS nennen den Merge, die neu gebaute Szene
und die Prüfung auf dem zusammengeführten Stand; Bericht des Player-Selbsttests
unter docs/port/logs/u4/smoke-macos-u5.3.json.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fortsetzung des angefangenen U5.3-Stands vom 2. Oktober.
- Fünf neue Sätze aus bake_pbr.py (metal, cloth, hide, bone, wood) für
Türme, Ancients, Grotte und die Schlundkrone. Ringborkes Rinde (RB_Bark)
auf ihren eigenen UVs mit dem 4k-Satz (Rauigkeit zu ORM gepackt),
Normalen im Tangentenraum des Meshes. Aufnahmen aller drei Lanes.
- Befund: Seit U5 war die Welt halb so hell und ohne Grün (Mid-Lane
Helligkeit 0,27, Grün 0 %). Ursachen und Korrekturen:
- Die PBR-Albedos wurden über die Godot-Farben multipliziert (Rasen
etwa x0,05). Jetzt teilt der Shader jede Karte durch ihren Mittel-
wert; die Godot-Farbe bleibt der Durchschnitt, die Karte liefert
Struktur. Ebenso die Rauigkeit, wo das Material eine eigene hat.
- Normal- und ORM-Karten waren als sRGB-Farbe importiert. Jetzt
Normalkarte bzw. linear.
- bake_pbr.py verzerrte alle Muster 10:1 (Regenstreifen). Stein, Erde,
Laub, Wasser und die neuen Sätze ohne Maserung neu gebacken.
- Der Treffer-Flash ersetzte die Grundfarbe aller Materialplätze; im
Nahkampf waren die Armeen weiß und der Boss gelb. Jetzt Tönung der
eigenen Farbe je Platz, wenig Emission, 16 Stufen.
- Nebel 0,0085 verschleierte die Kartenansicht zu 35-50 %; jetzt 0,0045.
Ergebnis Mid-Lane: Helligkeit 0,41-0,44, Grün 31-39 % (U3: 0,45 / 27 %).
- Tests: EditMode 29/29, PlayMode 13/13, Verify 718/0, Kerntests .NET
457/457, Fingerabdrücke unverändert (DCE95C96556F3A1A, 7B8E43AEFC0D60C5).
- Leistung: A/B mit einem U5.2-Player unter gleicher Last, kein messbarer
Unterschied (91,4 gegen 93,8 fps Karte, 124,9 gegen 125,3 fps Mid).
- Messwerkzeug tools/port/png_stats.py; Doku U5-VISUAL (U5.3),
PORT-STATUS, PORT-QA; Bilder screenshots/u5.3/ als JPEG.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entscheidung des Projektinhabers vom 2. Oktober 2026: Weg 2 (Stufen)
statt Gleichziehen oder Drosseln. Der Lankorridor trägt die vollen
PBR-Sätze; Berge, Kluft und ferner Hintergrund behalten Farbe und
Steinschicht.
- LuneZones: Korridor von 22 m um eine Lane-Mittellinie, ein Gebäude
oder die Grotte. NearLane entscheidet die Stufe eines Weltknotens.
- Surface-Shader _Quality: 1 bindet Albedo, Normal und ORM triplanar;
0 lässt die neun Map-Samples weg und behält Farbe, Vertex-Tönung,
Steinschicht und Emission — das U2-Aussehen der Berge.
- LuneMaterialFactory: Spec.Quality, TerrainEdge.mat für die umgebenden
Berge; Randmaterialien binden keine PBR-Sätze.
- LuneWorldBuilder.ApplyTier: jeder Weltknoten jenseits des Korridors
bekommt _Quality 0 über einen MaterialPropertyBlock. Gebäude,
Einheiten, Wege, Wasser und der innere Boden bleiben Lane-Stufe.
- Nachweis: screenshots/u5/edge-mountains.png (Randstufe) und
lane-and-edge.png (Übergang Lane → Rand in einem Bild).
- Leistung (macOS-Player, 116 Einheiten): 133 fps Übersicht, 180 fps
Mid nah — auf dem Niveau des Slices, weil die Messfenster den
Korridor sehen. Die Ersparnis liegt in Weitwinkeln und am Rand.
- Tests: EditMode 29/29, PlayMode 13/13, Kerntests 457/457. Keine
Regeländerung.
- Dokumentation: U5-VISUAL (Entscheidung und Umsetzung), PORT-QA,
PORT-STATUS, KNOWN-BEHAVIOR-DIFFERENCES.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Die Mid-Lane steht auf Zielqualität (stilisierter Realismus). Die übrige
Karte bleibt auf dem U2-Stand, bis über den Weg entschieden ist.
- U5A: tools/blender/bake_pbr.py backt sechs nahtlose PBR-Sätze
(limestone, soil, bark, leaf, rock, water) mit Albedo, Normal aus dem
Höhenfeld (Sobel) und ORM (R AO, G Rauigkeit, B Metall), je 2k.
Torus-Mapping für Kantenfluss wie phase10/bake_bark.py.
- U5B: Luneraria/Surface trägt _AlbedoMap, _NormalMap, _OrmMap triplanar
über den Godot-Weltfarben; ORM steuert Rauigkeit, Metall und AO.
LuneMaterialFactory bindet je Oberfläche den passenden Satz, LN_Rock
den Felsensatz.
- U5C: Mid-Lane-Licht — Nebel (ExponentialSquared, Dichte 0,0085),
scharfe Schatten (Bias 0,02), Weißabgleich und Vignette, ACES und
Bloom leicht angehoben.
- U5D: Hit- und Angriffs-Flash über MaterialPropertyBlock (warm beim
Angriff, weißglühend beim Treffer), Turmblitze als dreipunktiger Funke
mit Breitenkurve und Farbverlauf. CaptureMidLane schreibt fünf
Nachweisbilder nach docs/port/screenshots/u5/.
- Leistung (macOS-Player, 116 Einheiten): 132 fps Übersicht, 182 fps Mid
nah — 20–25 % unter U3 durch PBR, Normals und Nebel. Mid-Lane bleibt
über 120 fps.
- Tests: EditMode 29/29, PlayMode 13/13, Kerntests 457/457. Keine
Regeländerung; Golden 51.221 Werte unverändert.
- Grenze eingehalten: keine prozeduralen Gesichter, Haare oder Anatomie.
Sculpts bleiben vorbehalten (Freigabe und Lizenzprüfung).
- Dokumentation: U5-VISUAL (Umsetzung, Nachweis, Entscheidungsvorlage
für die ganze Karte), PORT-QA (U5), PORT-STATUS, KNOWN-BEHAVIOR-
DIFFERENCES.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Der M4-Umfang ist als Protokoll 4 portiert, serverautoritativ. Der Host
besitzt LuneMatch und rechnet jeden Kampf; Clients senden nur Absichten
und zeigen den Kampf aus Host-Momentaufnahmen.
- LuneSession (Core/Net): Rollen offline/Host/Gast, sechs Sitze, Lobby,
Hallo mit Protokollprüfung und Namenskürzung, Beitritt und Wieder-
einstieg über den Anzeigenamen, private Planung mit Spoof-Schutz,
Bereit ist verbindlich, Bots planen einmal je Runde, Disconnect gibt
den Platz an einen Bot (nie Kernverlust), Übernahme verwirft den
unbestätigten Bot-Entwurf, Revanche hält die Plätze, Hostverlust
meldet und führt ins Menü zurück.
- Kampfsynchronisation: Beginn mit Einheitenätzen und Gebäude-HP, alle
0,05 s neue Einheiten und ein Frame (13 Werte je Einheit), späte
Frames über die Serial verworfen, Gast interpoliert (frame_alpha).
- Transport: LuneLoopback (In-Prozess) für die Tests, LuneTcp + LuneWire
(Cursor-Codec) für Echtverbindungen statt ENet; ein Socket je Gast.
- Oberfläche: LuneMainMenu (Offline/Hosten/Beitreten, Bund, Lane, Name,
Adresse, Port) als Startbildschirm, LuneNetPlay als Schale wie
lune_main.gd. LuneGame leitet Befehle, Rückgängig und Bereit im
Netzspiel über die Sitzung; Tempo und Pause bestimmt der Host.
- Tests: NetSuite 43/43 (Port von test_lune_net.gd), NetRoundsSuite
12/12 (Port von net_rounds.py: 5 Runden, Prüfsummen gleich, Gast
rechnet 0 Schritte, Drop und Wiedereinstieg auf denselben Sitz),
LuneWireTests Round-trip. EditMode 29/29, PlayMode 13/13, Kerntests
457/457. Fingerabdrücke der Bot-Partien unverändert.
- Dokumentation: U4-NETWORK (Abnahme, Grenzen), PORT-QA (U4), PORT-STATUS
(U4 fertig, U5 nächster Schritt), KNOWN-BEHAVIOR-DIFFERENCES.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Das G3-HUD ist abgenommen; der Meilenstein U3 ist damit fertig.
- Prüfung (Port von verify_g3, Teile A–H plus I): 718 Prüfungen ohne
Fehler. Teil I prüft die Feld-Darstellung um das HUD (U3-Zugabe aus
dem Motivvergleich): Aufstellungsflächen, Grotteneingang, ruhender
Boss, Namensschilder, Eigentümer-Ring, Ancient-Balken.
- Feld um das HUD: Namensschilder für Helden (mit Stufe), Angriffs-
champions und den eingesetzten Boss („für Blau“), Eigentümer-Ring,
Ancient-Balken bei Schaden, ruhende Schlundkrone auf dem Podest,
eigener Grotteneingang, Aufstellungsflächen als eigene Objekte.
- Schriften korrigiert: Die Referenz deklariert Cantarell 560/700–760
und Cinzel 700, wendet die Gewichte aber nie an (variation_opentype
mit dem String-Schlüssel „wght“ wird von Godot ignoriert). G3 zeigt
Regular 400, der Port ebenso — Cinzel-Regular statt Bold, keine
Kontur zur Aufdickung. Laufweite aus spacing_glyph umgerechnet;
dunkler Saum als Schatten statt TextCore-Kontur.
- Werkzeuge: HudViewsTests (14 G3-Motive), HudPlaytest (Spieltest über
die echte Oberfläche per Befehlsdateien), ui_ms_per_frame im
LuneBenchmark. Layout folgt den echten Panelhöhen, Kamera startet wie
Godot _ready auf der eigenen Lane.
- Tests: EditMode 23/23, PlayMode 13/13, Kerntests 402/402, Verify
718/0. Fingerabdrücke der Bot-Partien unverändert (DCE95C96556F3A1A,
7B8E43AEFC0D60C5).
- Bilder: 14 Motive bei 1920×1080, Auflösungen 1152×720 bis 2560×1440,
Prüf-Schlüsselbilder, Spieltest-Screenshots.
- Leistung (macOS-Player mit HUD, 116 Einheiten): 169 fps Übersicht,
218 fps Mid nah; HUD-Skripte 0,090 bzw. 0,078 ms je Bild.
- Dokumentation: U3-UI (U3D, Schriftbefund), PORT-QA (U3), PORT-STATUS
(U3 fertig, U4 nächster Schritt), KNOWN-BEHAVIOR-DIFFERENCES.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Alle 86 Modelle der Godot-Referenz laufen durch die Blender→FBX-Pipeline
(nach bestandenem Vertical Function Test); jede Einheit zeigt ihr eigenes
Modell.
- Exportmanifest aus den Godot-Manifesten (tools/blender/make_manifest.py):
Units, Enemies, Props, Characters, Peoples, Buildings, Environment; die
drei Vergleichs-GLBs als Aliase. Neu in der Pipeline: Tangenten berechnet
Unity mit MikkTSpace, Generatoren laufen in einer temporären Kopie, die
Grüne Kluft wird wie das GLB zusammengefasst, Texturen kommen mit.
1.616 Blender- und 1.247 Unity-Prüfungen grün, zwei Exportläufe
byteidentisch; Kontaktbögen je Gruppe.
- Einheitenbibliothek nach Godots AssetLibrary: 70 Einträge der
Einheitengruppen, Figuren mit Skelett ersetzen das starre Modell ihrer ID.
Starre Modelle werden zur Laufzeit je Material zusammengefasst; Controller
werden an Ort und Stelle aktualisiert.
- Tests mit allen Modellen: EditMode 11/11, PlayMode 2/2. Vertical Function
Test Seed 2 DCE95C96556F3A1A und Seed 9 ab Runde 21 7B8E43AEFC0D60C5,
beide gleich dem Kern (Nachweise mit LUNE_EVIDENCE=u2a-batch; die Belege
von U2C und U2D bleiben unverändert).
- macOS-Player mit allen Modellen: 158-160 fps in der Übersicht
(116 Einheiten), 205-207 fps auf der Mid-Lane; Haupt- und Render-Thread
etwa doppelt so lang wie mit dem Platzhalter, Present-Ausreißer kürzer.
- Befund iCloud Drive: Konfliktkopien ("Name 2.ext") im Build-Cache ließen
den Build die Einheitenbibliothek mit altem Feldlayout schreiben; der
Player meldete sharedassets0.assets als beschädigt. LunePlayerBuild
entfernt solche Kopien vor dem Build und bricht ab, wenn während des
Builds neue entstehen. Bereits committete Kopien: Controller-Duplikate und
World/Generated 2.meta entfernt, drei U2D-Benchmarkläufe als -run1 bis
-run3 benannt.
- Dokumentation: U2-WORLD (Batch-Import), PORT-STATUS (Entscheidungen:
Modelle direkt in Git, Projektort außerhalb von iCloud Drive), PORT-QA.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vollständige Bot-Partien sichtbar in Unity, gleich der Partie des Kerns
(Vertical Function Test vor dem vollständigen Asset-Import).
- VerticalFunctionTests (PlayMode): Seed 2 von Runde 1 bis zum Fall des
Blau-Ancient (9 Runden; Türme fallen ab Runde 7, Grottenboss in Runde 8
gewonnen und in Runde 9 auf der Bot-Lane eingesetzt, bis zu 4 Helden) und
Seed 9 ab Runde 21 mit der Fixture des Golden-Szenarios high_wave_21 (bis zu
125 Einheiten, 6 Helden, Fall des Rot-Ancient). Beide Fingerabdrücke gleich
dem Kernlauf; 14 Bilder der Schlüsselmomente.
- macOS-Player-Build (LunePlayerBuild) und LuneBenchmark: 1080p, VSync aus,
116 Einheiten: 161-199 fps, Hauptthread 1,3 ms, Simulation unter 0,1 ms;
Ausreißer beim Present (p95 18-26 ms) analysiert und für U5 vorgemerkt.
- Dokumentation: U2-WORLD (U2D, Abnahme), PORT-STATUS, PORT-QA,
KNOWN-BEHAVIOR-DIFFERENCES (U2 ändert kein Verhalten), README.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Befund: Unitys Mono 6.13 rechnet float32-Zwischenwerte doppelt genau
(ECMA-335 I.12.1.3). Der erste Editor-Lauf fand 5 von 157 Golden-
Abweichungen: Blickrichtung bis 1,6e-3 rad; in mirror_match Runde 7 verliert
eine Einheit in Schritt 599 ihr Ziel, und der Kampf dauert 4,8 s länger.
Eine Toleranz ist dafür nicht begründbar.
Maßnahme: Vec2 rundet jeden Zwischenwert explizit auf float32 (conv.r4).
Keine Regeländerung, R1 unverändert. .NET 8: 402/402, Golden 0, Trace
byteidentisch zu vorher. Unity-Editor (Release und Debug): 402/402, Golden
bitgleich in allen Bereichen, Float-Probe 4000/4000.
- CoreIntegrationTests: keine Engine-Referenzen im Kern, Float-Arithmetik
wie Godot.
- docs/port/U1.5-UNITY.md: Versionen, Lizenz, Pakete, Tests, Golden je
Bereich, Float-Befund, Editor-Benchmark, fehlende Build-Module.
- docs/port/KNOWN-BEHAVIOR-DIFFERENCES.md mit "Legacy defects retained for
parity" (R1) und F1.
- Protokolle unter docs/port/logs/u1_5/.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vollständiger, engineunabhängiger Regelkern (Luneraria.Core, ohne
UnityEngine): Partie mit sechs Plätzen und zwei Teams, private Planung mit
atomarer Übernahme, Gold, Käufe, Aufwertungen, Formation, drei Lanes mit
zwei Laneturmen und zwei Basistürmen je Team, Ancients, unbegrenzte Wellen,
Helden mit Stufen, Items und Talenten, Angriffschampions, Bossgrotte mit
Anspruch, Entsendung, Kopfgeld und dreirundiger Sperre, Bots und
Siegbedingung (nur Ancient-Fall). Serverautoritative Befehlsschnittstelle.
- Deterministisch: fester Takt, geordnete Maps, fortlaufende IDs, kein
Zufall, keine Uhr, keine Threads
- Tabellen einmal aus Godot erzeugt (tools/port/gen_content.py)
- Golden-Referenzen aus Godot (tools/godot-golden): 19 Szenarien,
120 Snapshots, 51.221 Werte, Abweichung 0 (Toleranzen dokumentiert)
- Tests: content 75, core 91, m2 73, golden 157, determinism 6 = 402/402
- Leistung (M5): Simulationsschritt 0,259 ms statt 1,587 ms in GDScript
- Referenzfehler R1 im Bot-Gedächtnis bewusst übernommen und dokumentiert
- Geplante Helden (Lucy, Ghaliga, Siegfried, Feena) im Datenmodell, inaktiv
- Doku unter docs/port (U1-RULES, PORT-STATUS, PORT-QA, U2 bis U5)
Unity-Editor-Lauf offen: Die Unity-Lizenz ist noch nicht aktiviert; gebaut
und getestet mit dem .NET 8 SDK auf Unitys Sprachstand (C# 9, .NET
Standard 2.1).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>