Commit Graph
100 Commits
Author SHA1 Message Date
RichardandClaude Opus 5 c1e13f5441 WebUI: Server-Einstellungen ohne Geheimnisse bearbeiten
Umsetzung von #561.

Entscheidung Richard, 13.09.2026: Alles, was keine Geheimnisse beruehrt, soll
ueber das WebUI gehen; Geheimnisse ausschliesslich im Desktop.

Eine ausdrueckliche Freigabeliste (ServerSettingsCatalog) statt Reflection. Der
Desktop zeigt per Reflection alles, was ServerSettings hat. Uebernaehme das
WebUI das, stuende jedes kuenftige Feld automatisch im Netz, auch ein
Geheimnis.

Bearbeitbar, je Feld mit Pruefung:
- Farbschema und Zeitzone: nach Neustart
- VPN an/aus und VPN-Standort: sofort
- Blockchain-Listener: nach Neustart
- Polymarket-WSS: sofort
- Watchdog an/aus, Source, Instance und Intervall: sofort

"Sofort" und "nach Neustart" sind am Code belegt, nicht am Feldnamen geraten.
Zeitzone und Blockchain-Listener werden nur beim Start gelesen, das Farbschema
haelt der ThemeManager.

Nur im Desktop, Aenderungsversuch 403 und protokolliert:
- Geheimnisse: Mullvad-Account, Polygon-RPC-URL (enthaelt den Alchemy-Key),
  Watchdog-Token, Lizenzschluessel
- Watchdog-URL: an diese Adresse geht der Watchdog-Token, wer sie aendert,
  bekommt ihn
- Mullvad-CLI-Pfad: dieses Programm wird ausgefuehrt

Von den Geheimnissen zeigt das WebUI nur, ob sie gesetzt sind. OpenRouter- und
Master-Key werden dafuer nicht gelesen.

Gefunden dabei: MullvadVpnService baut die Kommandozeile als eine Zeichenkette
("relay set location <Wert>"). Der VPN-Standort nimmt deshalb nur Mullvad-
Kennungen an (cz, cz-prg). "cz account login 999" wird abgelehnt, ein Test
haelt das fest. Source und Instance gehen als JSON ans Deploymentcenter und
sind auf Kennungszeichen begrenzt.

POST prueft alle Werte zuerst und schreibt dann alles oder nichts, ueber
ServerSettingsFile. Danach zieht er den laufenden Stand nach: das Singleton,
MullvadVpnService.ReloadSettings und WatchdogHeartbeatService.ReloadSettings.

Desktop - bisher schrieb er eine WebUI-Aenderung still zurueck:
Die Einstellungen wurden einmal beim Oeffnen geladen, und "Speichern",
"Watchdog-Token setzen" und "Lizenzschluessel setzen" schrieben jeweils das
ganze alte Objekt zurueck. Jetzt:
- Speichern vergleicht innerhalb der Dateisperre den Dateistand vom Laden und
  verweigert, wenn sich die Datei inzwischen geaendert hat.
- Token und Lizenzschluessel schreiben nur noch ihr eigenes Feld.
- Eine unlesbare Datei sperrt das Speichern, statt Vorgaben zu zeigen, die
  beim Speichern die Schluessel geloescht haetten.

Die WebUI-Ansicht zeigt je Feld den Wirkungsvermerk und schickt nur, was
geaendert wurde. Der Leak-Test legt seine Kanarienwerte jetzt auch in die
Einstellungsdatei, sonst liefe die neue Route gegen eine leere Datei.

Nicht durch Unit-Tests abgedeckt: die Desktop-Aenderung an SettingsWindow
(Oberflaechenklasse). Sie wird mit der Sichtpruefung auf der VM abgenommen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 14:12:00 +02:00
RichardandClaude Opus 5 68d8d6f8d2 Module im WebUI aktivieren und deaktivieren
Umsetzung von #560.

Die Ansicht "Moduleinstellungen" zeigte bisher nur an, ob ein Modul laeuft. Jetzt
laesst sich dort wie im Modul-Tab des Desktops festlegen, welche Module beim
naechsten Start geladen werden. POST /api/modules/{name}/enabled nimmt den
gewuenschten Zustand ausdruecklich entgegen ({"enabled": true|false}) und
schaltet nicht einfach um. Zwei Klicks aus zwei Fenstern heben sich damit
nicht auf, und ein wiederholter Aufruf aendert nichts mehr.

Fehlerfaelle:
- Unbekanntes Modul: 404.
- Modul mit Aktivierungs-Blocker: 409.
- Fehlender Zustand: 400. Die Pruefung war zuerst lueckenhaft, der Test hat es
  gefunden: Mit "bool Enabled" machte ein leerer Rumpf {} daraus false, und ein
  unvollstaendiger Aufruf haette das Modul deaktiviert.

Gemeinsame Quelle statt Kopien:
- KnownModules: Die Modulliste stand viermal im Code (Program, CoreViews,
  ModuleViews, hartkodiert im WebUI). Der Start registriert jetzt die eine
  Liste.
- ModuleActivationView: Die Statusregeln des Desktops ("Aktiv - stoppt nach
  Neustart" usw.) liegen im Core. Desktop und WebUI zeigen dasselbe.

ServerSettingsFile - gefunden, bevor das WebUI in die Datei schreiben durfte:
ServerSettings.Load verschluckt jeden Lesefehler und liefert Vorgaben. "Frisch
lesen, ein Feld aendern, speichern" haette eine gesperrte oder beschaedigte
server_settings.xml durch Vorgaben ersetzt, und mit ihr Lizenzschluessel,
Watchdog-Token, Mullvad-Account und Alchemy-Key. Genau so schrieb auch der
Modul-Schalter des Desktops. ServerSettingsFile:
- liest streng und schreibt bei unlesbarer Datei nichts,
- schreibt atomar ueber eine Nachbardatei,
- erhaelt unter Linux die Dateirechte,
- serialisiert Aenderungen prozessweit.
Der Desktop-Schalter benutzt ihn jetzt ebenfalls.

Tests: Lizenzschluessel, Token und Alchemy-Key bleiben beim Umschalten in der
Datei; eine kaputte Datei bleibt Byte fuer Byte unveraendert und die Anzeige
bietet dann kein Umschalten an; Blocker, 404, 400, Idempotenz; die
Statustabelle; strenges Lesen, atomares Schreiben und Rechte am Dateiobjekt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 14:03:31 +02:00
RichardandClaude Opus 5 6498a3d0ec Pause stoppt jetzt auch Verkaufsleitern und Auto-Redeem
Behebt #570.

"Trading pausieren" hielt drei Wege nicht an, die Orders am CLOB platzieren:

1. SellLadderService: Eine laufende Verkaufsleiter preiste alle 5 s weiter
   nach, storniert und neu platziert. Sie pruefte weder Pause noch Modus. Die
   Engine ignoriert bei Pause zwar alle Signale, die bereits laufende Leiter
   lief aber ungebremst.
2. TraderMonitorService: Der REST-Pre-Redeem feuert aus der
   Positions-Synchronisierung, die bewusst auch bei Pause weiterlaeuft. Er
   pruefte nur LiveTradingMode.
3. PolymarketWssClient: Die Pause wurde nur beim Verbindungsaufbau geprueft.
   Auf einer bereits offenen Verbindung loesten Kursmeldungen den Auto-Redeem
   weiter aus.

Die Ursache ist allen gemeinsam: Jeder Dienst hat seine Sperre selbst
nachgebaut, und jeder hat etwas anderes vergessen. Die Regeln liegen jetzt an
einer Stelle, in TradingGate, und alle drei benutzen sie:
- Verkaufsleiter: Pause oder Modus des Kontotyps "Inaktiv" friert sie ein,
  bei "Nur Verkauf" laeuft sie weiter. Das entspricht der Engine.
- Pre-Redeem (REST und WSS): wie bisher nur bei Modus Aktiv, jetzt zusaetzlich
  nicht bei Pause.

Eine eingefrorene Leiter storniert nichts und platziert nichts. Das gilt auch
am Floor, wenn dort die ruhende Order fehlt. Die ruhende GTC-Order bleibt am
Buch, genau wie beim Beenden der Anwendung. LastActionAt bleibt unveraendert,
nach der Freigabe geht es an der aktuellen Stufe weiter. Protokolliert wird
einmal beim Einfrieren und einmal beim Fortsetzen, nicht alle 5 s.

CLOB-kritisch, deshalb:
- Vor der Aenderung gesichert unter agentspace/scripts/backups/*.vor-570-*.bak.
- Orderaufbau und Preislogik sind nicht angefasst. Der Diff umfasst eine Sperre
  und drei Bedingungen.
- Die Sperre steht vor dem ersten CLOB-Zugriff.

Die Harness von SellLadderServiceTests setzt jetzt Live = Aktiv. Mit dem
Standard Inaktiv waere Floor_replaces_order rot geworden, und Floor_holds_...
waere gruen geblieben, aber aus dem falschen Grund: keine Order, weil
eingefroren, nicht weil die Order noch ruht.

Neu in SellLadderFreezeTests: Pause, Inaktiv, "Nur Verkauf", Floor im
eingefrorenen Zustand, Fortsetzen an der aktuellen Stufe, dazu die
Entscheidungstabellen von TradingGate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 13:55:39 +02:00
RichardandClaude Opus 5 d33d695db5 WebUI: Trading beenden, ohne die Anwendung zu beenden
Umsetzung von #563.

Entscheidung Richard, 13.09.2026: Beenden soll ueber das WebUI gehen, aber
beschraenkt auf das Trading. Ein Ende der ganzen Anwendung naehme den Webserver
mit; danach waere das WebUI nicht mehr erreichbar.

POST /api/dashboard/stop-trading setzt Live- und Demo-Modus auf Inaktiv und
schaltet die Pause ein. Damit halten CopyTrading und ResolutionFarming (#569)
an, wie beim Ende der Anwendung. Offene Orders an der Boerse werden bewusst
nicht storniert: Das tut auch das Beenden der App nicht, und ein Eingriff in
die CLOB-Integration gehoert nicht in einen Notschalter. Der Dialog sagt das
ausdruecklich.

Die Route verlangt {"confirmed": true}. Ein Aufruf ohne Absicht, etwa aus einem
alten Skript, beendet nichts. Der Vorgang wird als Warnung protokolliert, mit
den Modi vorher.

Im Dashboard steht unter der Notfall-Pause jetzt "Trading beenden ...". Der
Dialog ist wie im Desktop 10 Sekunden gesperrt, Abbrechen und Esc gehen
jederzeit. Wieder aufgenommen wird nur ueber die Modus-Schalter. Die Pause
aufzuheben genuegt nicht, das haelt ein Test fest.

Offen bis #570: Laufende Verkaufsleitern und der REST-Pre-Redeem pruefen die
Pause nicht. Der Inaktiv-Modus, den dieser Knopf setzt, sperrt den Pre-Redeem
bereits; die Leitern friert erst #570 ein.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 13:51:24 +02:00
RichardandClaude Opus 5 99172a6be2 WebUI gibt keine Geheimnisse mehr heraus und aendert keine Zugangseinstellungen
Behebt #562.

Entscheidung Richard, 13.09.2026: Geheimnisse verwalten wir ausschliesslich im
Desktop.

Bis dahin lieferte GET /api/settings/webui das Zugangs-Token im Klartext. Ueber
das WebUI liessen sich ausserdem ein Token setzen, ein neues erzeugen und
LocalOnly abschalten. Wer das Token hatte, konnte das WebUI damit ueber
unverschluesseltes HTTP ins Netz oeffnen, sich den Zugang verlegen oder sich
selbst aussperren.

Jetzt:
- GET /api/settings/webui liefert Enabled, Port, LocalOnly und vom Token nur
  hasToken.
- POST /api/settings/webui und /webui/generate-token antworten mit 403 und
  protokollieren den Versuch. Sie bleiben als ausdrueckliche Ablehnung stehen:
  Ohne eigene Route faengt die Fallback-Route den POST ab und antwortet mit 200,
  ein altes Skript hielte das fuer einen Erfolg.
- Die WebUI-Einstellungsansicht zeigt den Zugang nur noch an. Gepflegt wird er
  im Desktop unter Einstellungen -> WebUI.

WebUiSecretsTests zaehlt alle GET-Routen selbst auf und prueft jede Antwort
gegen Kanarienwerte. Geprueft werden ApiKey, ApiSecret, ApiPassphrase und
PrivateKey eines Kontos, Mullvad-Account, Alchemy-Key, Watchdog-Token,
Lizenzschluessel und das WebUI-Token. Eine neue Route, die ein Konto oder die
Server-Einstellungen serialisiert, faellt damit auf, ohne dass jemand an diesen
Test denken muss. Gegen die alte Route schlug er fehl ("GET /api/settings/webui
liefert ein Geheimnis aus"), jetzt ist er gruen.

Ausserdem festgehalten: /api/accounts kennt nur GET. Polymarket-Konten bleiben
im WebUI lesbar und nicht aenderbar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 13:45:54 +02:00
RichardandClaude Opus 5 2278d1ccf3 ResolutionFarming haelt sich an Pause und Handelsmodi
Behebt #569.

GlobalTradingPaused, LiveTradingMode und DemoTradingMode wertete bisher allein
CopyTrading aus. Die Farming-Ausfuehrung pruefte nur RfSettings.Enabled und
eroeffnete weiter Positionen, auch wenn "Trading pausieren" gedrueckt war oder
der Demo-Modus auf Inaktiv stand. Der Pause-Knopf hielt damit nur die Haelfte
an.

Echtes Geld war noch nicht betroffen: RF fuehrt nur Demo-Konten aus, die
Live-Ausfuehrung wird als Zielland-Arbeit uebersprungen. Mit der
Live-Anbindung haette eine Pause ohne Wirkung vor echten Positionen gestanden.

Jetzt gelten dieselben Regeln wie im CopyTrading. Die Pause sperrt, und der
Modus des Kontotyps (Demo oder Live) muss auf Aktiv stehen. "Nur Verkauf"
sperrt ebenfalls, denn Farming kauft ausschliesslich. Protokolliert wird nur
der Wechsel zwischen gesperrt und frei, nicht jeder Fuenf-Minuten-Durchlauf.

VERHALTENSAENDERUNG: Demo-Farming eroeffnet nur noch bei Demo-Modus = Aktiv.
Bisher lief es unabhaengig vom Modus, und der steht nach jedem Start auf
Inaktiv.

Bewusst nicht gesperrt ist die Aufloesungsueberwachung. Sie bucht nur Maerkte
ab, die bereits aufgeloest sind, und sendet keine Orders. Hielte man sie an,
wiche der ausgewiesene PnL von der Wirklichkeit ab. Der Scanner schreibt nur
Kandidaten und bleibt ebenfalls aktiv.

Der Schleifenrumpf liegt jetzt als RunCycle() vor und ist damit testbar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 13:40:45 +02:00
RichardandClaude Opus 5 b70d5e5f00 WebUI-Tests rufen jetzt echte Routen auf
Behebt #568.

Keine der Testdateien mit "EndpointsTests" im Namen hat je einen Endpunkt
aufgerufen. CopyTradingAndResolutionFarmingEndpointsTests beruehrte gar keinen
Produktionscode: Die Tests summierten Listen im Test und verglichen das Ergebnis
mit sich selbst. Modules_KnownModules pruefte, ob ein Array seine eigenen
Elemente enthaelt. Settings_UpdateRequest pruefte die Portbegrenzung an einer im
Test nachgebauten Lambda. Solche Tests bleiben gruen, egal was der Endpunkt tut.

Neu startet WebUiTestHost das WebUI in einem Testserver
(Microsoft.AspNetCore.TestHost) und spricht es ueber HTTP an. Damit der Test
die Kette aus dem Betrieb prueft und keine nachgebaute, liegt sie jetzt in
UsePolyTraderWebPipeline(): statische Dateien, Token-Pruefung, alle Routen.
ConfigurePolyTraderWeb ruft genau diese Methode. Ersetzt wird nur, was
ausserhalb des Prozesses liegt - Kestrel durch den Testserver, MySQL durch den
InMemory-Provider.

Die acht CopyTrading/ResolutionFarming-Tests pruefen dieselben Absichten wie
vorher, jetzt an der Antwort der Route. Neu hinzugekommen sind Tests fuer:
- Zugangssperre: ohne Token, mit falschem Token, ohne konfiguriertes Token
- die Modulliste
- Job-Umschalten samt 404
- die Ablehnung einer leeren Supervisor-Frage

Die beiden Tests, die schon echten Code prueften, bleiben.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 13:38:19 +02:00
RichardandClaude Opus 5 2c0ab79dcd WebUI-Kopfleiste: Aufklappmenues statt elf Tabs
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
Umsetzung von #541, folgt auf #532.

Elf Tabs nebeneinander waren nicht mehr zu ueberblicken. Die Leiste hat jetzt
vier Eintraege, gruppiert nach dem, was man dort tut:

- Dashboard
- Analytics: Analytics, Accounting, Supervisor
- Module: Moduleinstellungen (die allgemeine Modulansicht), danach alle Module
- Einstellungen: Einstellungen, Jobs, Konten, Terminal / Logs

Supervisor und Accounting stehen unter Analytics und zusaetzlich in der
Modulliste, weil dort alle Module stehen sollen. Hervorgehoben wird das
Oberelement nur an ihrem Hauptplatz (Analytics); der zweite Zugang traegt
data-secondary. Sonst leuchteten bei geoeffnetem Supervisor zwei Menues.

switchView() findet den aktiven Eintrag jetzt ueber data-view statt ueber eine
Teilzeichenkette im onclick-Attribut. Das alte Verfahren hing am Zufall der
Namen: Eine Ansicht, deren Name in einer anderen enthalten ist, haette beide
markiert.

Die Modulliste zeigt den Zustand aus /api/modules: Ein deaktiviertes Modul
erscheint ausgegraut mit "deaktiviert" und ist nicht anklickbar, statt in eine
leere Ansicht zu fuehren. Ein Modul, das der Server fuehrt, fuer das es im
WebUI aber keine Ansicht gibt, wird mit "keine Ansicht" gelistet.

Bedienbar mit Maus und Tastatur: Klick ausserhalb und Esc schliessen (Esc gibt
den Fokus ans Oberelement zurueck), Pfeil nach unten oeffnet und springt in das
Menue, Pfeiltasten laufen um und ueberspringen deaktivierte Eintraege, Tab
verlaesst das Menue. aria-haspopup, aria-expanded und aria-current sind gesetzt.

Unter 760 px haengen die Menues an der ganzen Leiste statt am Eintrag. Bei
400 px ragte "Module" sonst 35 px ueber den rechten Rand. Ein Nachmessen per
Skript taugt dagegen nicht: In der Mobilansicht waechst der Layout-Viewport mit
dem Ueberstand mit, und die Messung meldet genau dann "passt".

Die Modulansicht heisst jetzt wie ihr Menueeintrag "Moduleinstellungen".

Geprueft auf der Linux-Test-VM im Browser: Alle 12 Eintraege schalten die
richtige Ansicht und heben das richtige Oberelement hervor, das Menue schliesst
danach; Tastaturbedienung, deaktiviertes und unbekanntes Modul (simuliert)
verhalten sich wie beschrieben. Vermessen bei 400, 700, 768 und 1024 px: kein
Menue ragt aus dem Fenster, die Seite scrollt nie waagerecht. 556 von 556 Tests
bestanden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 10:33:41 +02:00
RichardandClaude Opus 5 4c556be57d Einstellungen: erst schreiben, dann uebernehmen
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
Behebt #534.

Die vier schreibenden Endpunkte verschluckten die Ausnahme des Repositories und
meldeten anschliessend unbedingt Erfolg. Das Verschlucken war unschoen; die
Reihenfolge war gefaehrlich: copyState wurde auch dann geaendert, wenn die
Datenbank abgelehnt hatte. Das Modul handelte danach mit Risikolimits, die
nirgends standen, und nach dem naechsten Neustart konnte niemand mehr
rekonstruieren, womit es gehandelt hatte.

Neu geht der Schreibvorgang zuerst, und der Hauptspeicher wird nur nachgezogen,
wenn er gelang. Sonst 500 mit Klartext und unveraenderter Zustand. Fehlt die
Ablage ganz, ist die Aenderung ebenso rein fluechtig — auch das wird abgelehnt,
mit 503.

Betroffen: CopyTrading-Kontoeinstellungen, ResolutionFarming-Kontoeinstellungen,
Master-Trader anlegen/aendern, Master-Trader loeschen.

Dass alle vier denselben Helfer (PersistenceGuard) benutzen, ist der eigentliche
Punkt: Aus je eigenem try/catch je Endpunkt ist die Ungleichheit ueberhaupt erst
entstanden.

Bewusst anders behandelt bleibt das Archivieren eines Supervisor-Berichts: Die
Antwort des Agenten steht dort bereits und hat Geld gekostet: sie wegen eines
fehlgeschlagenen Archiveintrags zu verwerfen, waere schlimmer als der fehlende
Eintrag, und an diesem Schreibvorgang haengt kein Verhalten des Systems.
Stillschweigend verschwindet er aber nicht mehr, sondern wird protokolliert.

In der Oberflaeche zeigten die Schreibwege bisher nur "HTTP 500" an und
verschenkten damit genau die Begruendung, die der Server jetzt mitliefert.
errorText() liest sie aus der Antwort.

Entscheidung von Richard: ablehnen statt fluechtig uebernehmen. Damit sind
waehrend eines Datenbankausfalls keine Aenderungen an den Einstellungen mehr
moeglich; das Handeln selbst laeuft weiter.

Geprueft auf der Linux-Test-VM mit angehaltener MariaDB: alle drei Schreibwege
antworten mit 500 und nennen den Grund, das Limit bleibt bei 11,25 statt auf
99,99 zu springen, der Phantom-Trader entsteht weder im Hauptspeicher noch in
der Datenbank, jeder Fehlschlag steht im Protokoll. Nach dem Wiederanlauf
speichert es wieder. 556 von 556 Tests bestanden (5 neue).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 15:51:16 +02:00
RichardandClaude Opus 5 72ad38518b EZB-Tageskurse selbst abrufen, Kopfleiste umbrechen lassen
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
Behebt #532 und #533.

#532 — Kopfleiste bricht um statt zu scrollen

Mit elf Ansichten brauchte die Leiste 1623 px. Darunter scrollte sie seitlich
weg, ohne dass ein Hinweis darauf sichtbar war: Wer einen rechten Tab anklickte,
verlor "Dashboard" aus dem Blick und fand den Weg zurueck nicht mehr. Statt
overflow-x nun flex-wrap auf Leiste und Kopfzeile. Geprueft von 1920 bis 768 px
— nichts wird mehr abgeschnitten, der Koerper scrollt nie waagerecht.

#533 — Kurse holen, statt EUR still auf null zu setzen

Die Tabelle acc_fx_rates gab es seit A-2, befuellt hat sie nie jemand. Deshalb
war EUR nicht verfuegbar, und der PDF-Export machte daraus wortlos einen Beleg
mit lauter Nullbetraegen.

Neu holt EcbFxRateSource die amtlichen Referenzkurse ueber die EZB-Daten-API
(Reihe EXR/D.USD.EUR.SP00.A, CSV). FxRateSyncService stoesst das beim ersten
Ingest-Lauf des Tages an: erstmalig 400 Tage rueckwirkend, danach nur noch der
Rand. Die Kurse werden gespeichert, nicht bei Bedarf geholt — eine Abrechnung
fuer einen vergangenen Monat muss den Kurs von damals nehmen und beim naechsten
Aufruf dasselbe Ergebnis liefern.

Zwei Fallen, die dabei zu umgehen waren:

- Die Reihe liefert USD je EUR (1 EUR = 1,1652 USD), FxRate.UsdToEur meint die
  Gegenrichtung. Wer das verwechselt, bekommt eine Abrechnung, die um rund 35 %
  danebenliegt und trotzdem plausibel aussieht. Gespeichert wird der Kehrwert.
- Die CSV-Antwort enthaelt in TITLE_COMPL ein Komma innerhalb von
  Anfuehrungszeichen; naives Splitten verschoebe die Spalten.

Die Warnung erscheint, sobald der verwendete Kurs mehr als drei Tage vor dem
Stichtag liegt. Drei Tage, weil genau so gross die planmaessige Wochenendluecke
ist: Der Freitagskurs gilt bis Montag und ist dabei kein Mangel.

Der Beleg bleibt trotzdem erzeugbar — die Warnung steht sichtbar darauf und im
WebUI ueber der Abrechnung. Nur ohne jeden Kurs lehnt der Export jetzt mit 400
ab, statt Nullbetraege auszugeben. PDF und CSV laufen deshalb nicht mehr ueber
window.open: Eine nackte JSON-Fehlermeldung in einem neuen Reiter ist keine
Antwort. downloadExport() holt die Datei, meldet Fehler im Klartext und stoesst
sonst den Download an.

Nebenbei im Testlauf gefunden und behoben: Der manuelle Anstoss aus dem WebUI
und die stuendliche Schleife trafen sich in derselben Sekunde — im Log standen
"280 Kurse uebernommen" und "53 Kurse uebernommen" untereinander, beide hatten
die EZB gefragt. SyncDailyAsync serialisiert jetzt und prueft den Tag ein
zweites Mal innerhalb der Sperre.

Geprueft auf der Linux-Test-VM gegen die echte EZB-API: 280 Kurse vom
06.08.2025 bis 09.09.2026 uebernommen, Umrechnung stimmt (1/1,1652 = 0,858222),
eine Maerz-Abrechnung nimmt den Kurs vom 31.03. und nicht den heutigen, das
Warnbanner erscheint ab dem vierten Tag, der Export verweigert ohne Kurs und
liefert sonst ein gueltiges PDF. 551 von 551 Tests bestanden (18 neue).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 15:25:47 +02:00
RichardandClaude Opus 5 dcc764dec1 WebUI: Module, Analytics und Buchhaltung als eigene Ansichten
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
Das WebGUI konnte bisher Dashboard, Konten, Jobs, Logs und Einstellungen.
Die vier Strategie- und Analysemodule waren nur in der Avalonia-Oberflaeche
erreichbar - wer den Server aus der Ferne bediente, sah sie nicht.

Fuenf neue Endpunktgruppen holen sie herein:

  /api/analytics                  KPIs, Equity-Kurve, PnL je Modul und Tag,
                                  durchsuchbare Trade-Historie mit Seitenlauf
  /api/modules/copytrading        Master-Trader (CRUD), offene und
                                  geschlossene Trades, Risikolimits je Konto
  /api/modules/resolutionfarming  Scanner-Kandidaten, Positionen, Historie,
                                  Farming-Parameter je Konto
  /api/modules/supervisor         Profile, Agentenfragen, Berichtsarchiv,
                                  Signal-Dossiers, Counterfactuals
  /api/modules/accounting         BWA-Periodenabrechnung, Ledger-Journal,
                                  PDF- und CSV-Export, Ingest-Laeufe

Dazu im Bestand:
- Dashboard bekommt /overview-widgets: Modul-KPIs (heute/7T/30T), auffaellige
  Trades der letzten 24 Stunden, Warnungen und Fehler des Tages, den letzten
  Supervisor-Bericht.
- Die Kontenliste zeigt 3-Tage-PnL, Winrate, Gesamtergebnis und die
  beteiligten Module statt nur Salden.
- Jobs lassen sich ueber /toggle und /state ein- und ausschalten, nicht nur
  ausloesen.

Die Oberflaeche bleibt ohne Fremdbibliotheken: alle Diagramme sind Inline-SVG,
kein CDN, kein npm. Alle neuen Pfade liegen unter /api/ und damit hinter der
bestehenden Token-Pruefung.

Zwei Fehler nebenbei behoben:

- AccountingReportService.ResolveCurrency lief in eine NullReferenceException,
  wenn der FX-Dienst nicht gesetzt war. Betrifft jeden EUR-Aufruf ohne
  geladene EZB-Kurse.
- Ein Master-Trader, dessen Name ein Apostroph enthaelt, hatte einen toten
  Loeschen-Knopf: escapeHtml laesst ' unberuehrt, und im onclick-Attribut
  beendete das Zeichen das JavaScript-Literal vorzeitig. Laengerer Text mit
  Anfuehrungszeichen konnte darueber eigenen Code einschleusen. Neu setzt
  jsArg() den Wert als JSON-Literal ein; geprueft mit
  O'Brien "quote" <b>bold</b> \ backslash.

McpLightServerTests weicht jetzt aus, wenn HttpListener mangels URL-ACL nicht
binden darf, statt den Lauf scheitern zu lassen.

Geprueft auf der Linux-Test-VM (Ubuntu 26.04, .NET 10): Build ohne Fehler,
533 von 533 Tests bestanden, alle 11 Ansichten und 15 Unteransichten geladen,
alle Endpunkte mit 200 beantwortet, Schreibwege bis in die Datenbank
nachverfolgt, PDF- und CSV-Export gueltig, SSE-Logstrom live.

Offene Befunde aus der Abnahme liegen als #532 (Kopfleiste laeuft unter
1623 px ueber), #533 (EUR-PDF ohne EZB-Kurse liefert Nullbetraege) und #534
(Einstellungen melden Erfolg trotz gescheitertem Speichern) im Bugtracker.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 09:17:49 +02:00
Richard 78a2f85b94 Standardport für WebUI von 5001 auf 6001 geändert
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
2026-09-08 12:35:29 +02:00
Richard 10f928eb4e Paralleles WebGUI mit Kestrel, Token-Sicherung und SSE-Logs implementiert 2026-09-07 21:55:51 +02:00
RichardandClaude Opus 5 28b3aedec7 Vier Befunde der Sichtpruefung behoben: Farbschema, Grids, Diagramme, Kontrast
#383 Farbschema "System" kehrte sein Versprechen um. ThemeManager.IsDark verglich
ActualThemeVariant der Anwendung mit Dark; bei "System" steht dort Default, waehrend
die Fenster selbst nach hell oder dunkel aufloesen. IsDark war damit im
Auslieferungszustand immer false - Symbol, Beschriftung und Toggle() haengen alle an
diesem Wert. Gelesen wird jetzt die angeforderte Variante, bei "System" die
Betriebssystem-Einstellung. Derselbe Fehler steckte in Brush(): die Methode suchte bei
"System" in den hellen Farben, waehrend dunkel gezeichnet wurde - betroffen war genau
das, wofuer es sie gibt (Zeilenfarben, KPI-Vorzeichen). Neu ist ausserdem, dass eine
Umstellung am Betriebssystem ThemeChanged ausloest, solange "System" gilt.

#384 Sternspalten quetschten die Endspalten weg. Der Merksatz aus #56 galt bisher nur
fuer gridTraders. Angewandt auf gridOpen und gridClosed sowie auf die uebrigen Grids,
deren Spaltensumme den sichtbaren Bereich uebersteigt (gridTrades, gridJobs, gridLedger,
gridCandidates, gridPositions, gridHistory). Auto statt Stern, dazu MaxWidth 360 - anders
als "Name" in #56 traegt "Markt" ganze Fragesaetze und wuerde die Zahlenspalten sonst aus
dem Blick schieben. Grids mit weniger Spalten als Platz behalten ihre Sternspalte.

#385 Gewinntage wurden rot gezeichnet. Eine ColumnSeries hat genau ein Fill fuer alle
ihre Balken; gefaerbt wurde deshalb nach der Summe ueber alle Tage. Jetzt zwei Reihen an
denselben Positionen - Gewinne in der einen, Verluste in der anderen, Luecken als null.
"PnL je Modul" faerbt ebenfalls nach Vorzeichen: zwei Diagramme nebeneinander mit
verschiedenen Leseweisen waeren schlechter als beide ohne.

#386 Drei Kleinigkeiten. Die Equity-Achse beschriftete zehn Teilstriche mit zwei Daten -
unter drei Tagen kommt jetzt die Uhrzeit dazu, darueber gilt hoechstens ein Teilstrich je
Tag. "Deaktivierte Module" sah aus, als fehle das Bedienelement: leere Nur-Lese-Felder
zeigen jetzt "—" in einer abgesetzten Flaeche. Die Abschnittsbeschriftungen der
Seitenleiste lagen bei 3,65:1 statt der geforderten 4,5:1 (im Bild sogar 1,83:1, weil
10 px mit Sperrung ausduennen) - AppCaptionTextBrush erreicht 4,61:1 hell und 6,21:1
dunkel und bleibt deutlich leiser als die Eintraege darunter.

Build gruen, 486 Tests gruen. Die Sichtpruefung auf der Linux-VM steht noch aus; die
drei rein visuellen Punkte sind aus dem Quelltext begruendet, nicht im Bild belegt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 10:17:49 +02:00
RichardandClaude Opus 5 53231d62bc Testen laeuft jetzt ueber das Deploymentcenter; Befunde in den Bugtracker
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
Die Testanleitung im PolyTrader-Repo ist nur noch ein Zeiger auf die
massgebliche Fassung in Deploymentcenter/docs/TESTUMGEBUNG.md, plus dem, was
PolyTrader-eigen ist: Display :99, Datenbank polytrader_test, Dienstkonto,
Publish-Verzeichnis, /tmp-Praefix. Die Anleitung galt immer projektuebergreifend
und lag nur hier, weil sie beim ersten Linux-Lauf von PolyTrader entstand. Eine
Tabelle loest die alten Abschnittsnummern auf, damit vorhandene Verweise lesbar
bleiben.

Befundbericht: Nachtrag 6 haelt die Gegenprobe am Bild vom 28.08.2026 fest -
den ersten Lauf nach dem neuen Verfahren. Linux-Build 0 Fehler / 15 Warnungen
wie unter Windows, 484 Tests gruen, --smoke-ui unter xvfb-run -n 99 durchgaengig
gruen. B-6, B-7, B-11, B-13, B-14 und die B-12-Selbstheilung sind damit auf der
Zielplattform bestaetigt; B-9 hat sich als kein Fehler entpuppt, und die
Spaltenumstellung hatte einen eigenen Fehler erzeugt.

Damit ist dieser Bericht abgeschlossen. Was offen bleibt, steht ab jetzt im
Bugtracker (Items #50-#52 und #56 fuer polytrader, #53-#55 und #57 fuer
deploymentcenter) statt in Befundberichten - dort geht es nicht mehr verloren,
und Befunde an fremden Projekten landen dort, wo jemand sie beheben kann.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 21:06:34 +02:00
RichardandClaude Opus 5 57cfca5fe9 Testlauf, dem man glauben kann: Zeitzonen-Tests und Schluss mit Nebenlaeufigkeit
Zwei Tests zur Zeitzonen-Umstellung aus dem letzten Commit: der Zeitstempel
eines Logeintrags traegt den Versatz der ANZEIGE-Zone (nicht den des Systems),
und die abgelegte JSONL-Zeile traegt ihn mit. Sie liegen bewusst in
AppTimeZoneTests - dort steht der uebrige Zeitzonen-Zustand, und innerhalb einer
Klasse laufen Tests nacheinander.

Das genuegte aber nicht. Von sechs Laeufen fiel einer um und liess sich danach
nicht wieder einfangen. Die Ursache ist kein einzelner Test, sondern die Bauart:
Mehrere Bausteine halten prozessweiten Zustand, den Tests bewusst umstellen -
AppTimeZone, SecretProtection, die Diagnosezaehler von AccountIdSetJson. xUnit
fuehrt Testklassen standardmaessig nebenlaeufig aus, also sieht eine Klasse
mitten im eigenen Lauf, was eine andere gerade umgestellt hat.

Neu ist das nicht, aber die Zeitzonen-Umstellung hat es verschaerft: Seit die
Logzeitstempel der Anzeige-Zeitzone folgen, haengt jedes LogMessageEventArgs an
AppTimeZone - waehrend AppTimeZoneTests dieselbe Einstellung nach Auckland und
zurueck dreht.

Deshalb laufen die Testklassen jetzt nacheinander, und die Zaehlerpruefungen
arbeiten mit der Differenz statt mit absoluten Werten. Kosten: 4-5 s statt 3 s
Laufzeit. Ein Testlauf, dem man glauben kann, ist das allemal wert - danach
sechs Laeufe in Folge gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 21:06:18 +02:00
RichardandClaude Opus 5 f4e017fe58 Spalten wieder vollstaendig; die Kalender-Vermutung war falsch
Zwei Nacharbeiten aus der Sichtpruefung auf der Linux-VM vom 28.08.2026.

Master-Trader-Grid: Die Breitenumstellung von gestern hat mehr kaputtgemacht
als geheilt. Von zwoelf Spalten blieben sieben brauchbar - hinter "Winrate %"
stand eine Spalte mit abgeschnittenen Werten ohne Ueberschrift, dahinter vier
leere Streifen. PnL, Copy-PnL, Profit-Faktor, Ø PnL/Trade und Copy-Trades waren
weder lesbar noch als Spalte erkennbar. Das ist schlimmer als der urspruengliche
Befund: dort fehlten Ueberschriften, hier die Werte.

Ursache war die Sternbreite auf "Name". Zwoelf Spalten passen neben dem 460 px
breiten Detailbereich nicht ins Fenster; statt waagerecht zu schieben, verteilt
das DataGrid den Mangel und zerdrueckt die Auto-Spalten am Ende. Jetzt steht
auch "Name" auf Auto: jede Spalte behaelt ihre Breite, das Grid bekommt einen
waagerechten Rollbalken. Im Bild gegengeprueft.

Kalendersymbol (Befund B-9): zurueckgenommen. Die gestrige Aenderung war eine
Vermutung, und sie war falsch. Die vermeintlich sinnlose Zahl im Datumsfeld ist
das heutige Datum - am 26.08. eine "26", am 28.08. eine "28". Avalonia zeichnet
dort die heutige Tageszahl in ein Kalenderblatt, unter Linux fehlt der
Blatt-Glyph. Zwei Gegenproben liessen das Bild unveraendert: die Formatvorlage
per :not(#PART_Button) vom Knopf ferngehalten, und das Farbschema gewechselt.
Eine Aenderung ohne Wirkung und ohne Begruendung gehoert nicht in den Code; an
ihrer Stelle steht ein Kommentar, damit der Naechste nicht dieselbe Spur
verfolgt. Rein kosmetisch, Bugtracker-Item #50.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 21:05:49 +02:00
RichardandClaude Opus 5 9b2294cb4c Testanleitung: eigenes X-Display je Projekt fuer Parallelbetrieb
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
Damit mehrere Agenten gleichzeitig Oberflaechen testen koennen, bekommt jedes
Projekt eine feste Displaynummer (Vorgabe Richard):

  :99 PolyTrader, :98 Predictalytics, :97 ClawdDotNet, :96 IBKRTrader,
  :95 und absteigend fuer kuenftige Projekte.

Zwei Prozesse auf demselben Display sehen die Fenster des jeweils anderen -
Klicks landen im falschen Programm, Aufnahmen zeigen fremde Anwendungen.

Beim Durcharbeiten fielen zwei weitere Kollisionspunkte auf, die zum
Parallelbetrieb dazugehoeren und mit aufgenommen wurden:

- Screenshot- und Logdateien in /tmp brauchen ein Projektpraefix. /tmp/v_1.png
  ueberschreiben sich parallel laufende Projekte gegenseitig.
- "xvfb-run -a" darf NICHT mehr verwendet werden: Das -a sucht sich selbst ein
  freies Display und beginnt dabei bei :99 - ausgerechnet PolyTraders Nummer.
  Stattdessen "xvfb-run -n <nummer>".

Die Warnung ist nicht theoretisch: Auf der VM lag ein verwaister X98-Socket,
entstanden durch genau so einen "xvfb-run -a"-Aufruf beim smoke-ui-Test, als
:99 belegt war. Er blockierte Predictalytics' reservierte Nummer, ohne dass ein
Prozess lief. Entfernt, und die Anleitung erklaert jetzt, wie man verwaiste
Sockets erkennt (ls /tmp/.X11-unix/ gegen pgrep -a Xvfb lesen) und aufraeumt.

Weiter ergaenzt:
- pkill nie ohne Displaynummer - "pkill Xvfb" erschlaegt die Sitzungen aller
  anderen Projekte.
- DISPLAY in jedem Skript setzen, sonst landet man auf :0, dem echten Desktop.
- Die Skriptvorlage hat jetzt einen Kopf mit PROJEKT/DISP/FENSTER; das ist
  alles, was sich je Projekt unterscheidet. Praktisch gegengetestet.
- Aufraeumabschnitt und Belegungsliste um Displays und Verzeichnisse erweitert.

Nebenbei aufgefallen: Das PolyTrader-Publish lag unter ~/pt-test statt
~/polytrader-test und verletzte damit die eigene Verzeichniskonvention.
Umbenannt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 20:49:28 +02:00
RichardandClaude Opus 5 62570cfdd8 Sichtpruefung mit Testdaten: die Grids in Aktion, vier weitere Befunde
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
Testdaten in die Testdatenbank eingespielt (3 Demo-Konten, 5 Master-Trader,
3 offene Positionen, 7 Trades, 5 RF-Kandidaten), gesichert als
docs/pruefplaene/testdaten-ui.sql zur Wiederverwendung. Bewusst mit
42-stelligen Wallet-Adressen und langen englischen Marktfragen - kurze
Platzhalter haetten die Layoutbefunde verdeckt.

Mit Daten wirkt die Anwendung vollstaendig funktionsfaehig: Grids fuellen sich,
die Auswahl markiert Zeilen, das Detailformular uebernimmt den gewaehlten
Datensatz, zugewiesene Konten werden korrekt angehakt, KPI-Kacheln rechnen.

Vier weitere Befunde:
- B-13 (wichtig): Die Spalte "Name" im Master-Trader-Grid ist auf wenige Pixel
  zusammengequetscht - die Anzeigenamen sind NIRGENDS zu sehen, obwohl sie die
  wichtigste Information der Zeile sind. Die festen Breiten der elf uebrigen
  Spalten lassen der Sternbreite fast nichts uebrig.
- B-11 praezisiert: Nicht die Werte sind zu breit, sondern die Ueberschriften.
  Das RF-Grid zeigt lange Marktfragen mühelos, waehrend "Fee (bps)" zu
  "Fee (bp" verstuemmelt wird. Die Breiten sind auf die Datenwerte ausgelegt.
- B-14: Beschreibung und Reasoning sind einzeilige Felder fuer varchar(1000).
- B-15: Ein fehlerhafter Datensatz legt die gesamte Modul-Hydration lahm. Beim
  ersten Einspielen war AssignedAccountIds kein gueltiges JSON - daraufhin wurde
  kein einziger Trader geladen. Im Betrieb hiesse das: ein beschaedigter Eintrag
  legt das komplette Modul stumm, statt uebersprungen und gemeldet zu werden.

B-7 bestaetigt: In jeder KPI-Kachel steht der Modulname doppelt.

Nachgeprueft und KEIN Fehler: Copy-PnL zeigt 0,00, weil die Kennzahlen aus den
tatsaechlichen Copy-Trades berechnet werden und mod_copytrading_closed_trades
leer ist. Die Werte stehen auch in der Datenbank auf 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 22:59:15 +02:00
RichardandClaude Opus 5 a39ad67181 Modulfenster geprueft; Screenshot-Verfahren in die Testanleitung aufgenommen
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
Nach der Lizenzaktivierung durch Richard sind alle vier Module aktiv - die
Anwendung meldet "Lizenz gueltig (online geprueft)", der Cache steht auf valid,
die Statusleiste zeigt vier Module. Damit ist D-2 live abgenommen, inklusive
HWID v2 auf Basis der Linux-machine-id. Ein Stueck von Roadmap A3 nebenbei.

Vier weitere Befunde:
- B-9: In den Datumsfeldern erscheint statt des Kalendersymbols ein Artefakt.
  Die Icon-Schriftart fehlt unter Linux, Fontconfig ersetzt sie stillschweigend
  durch eine andere. Nur im Bild zu sehen, nie im Log.
- B-10 (schwerwiegend, im vorigen Commit behoben): kein einziges DataGrid wurde
  gerendert.
- B-11: Spaltenueberschriften werden abgeschnitten, die letzten drei Spalten
  zeigen gar keinen Text mehr. Genau der A5-Punkt Spaltenbreiten: die festen
  Pixelwerte stammen aus der WinForms-Fassung mit schmalerer Schrift. Nicht
  behoben - Spaltenbreiten legt man sinnvoll erst mit echten Daten fest.
- B-12: Der Lizenzschluessel liegt im Klartext in server_settings.xml, obwohl
  die Projektkonvention Verschluesselung at-rest vorsieht und der Code beides
  unterstuetzt.

Positiv: Die acht KPI-Kacheln im Accounting brechen sinnvoll um - eine offene
A5-Frage ist damit beantwortet.

docs/TESTUMGEBUNG-Linux-VM.md Abschnitt 4.7 neu: wie ein Agent Oberflaechen
eigenstaendig begutachtet - Xvfb dauerhaft starten, mit xdotool navigieren, mit
import aufnehmen, Ausschnitte vergroessern, Kontraste nachmessen. Mit den
Lehren aus diesem Durchgang: grosszuegige Wartezeiten, nur eine Instanz
gleichzeitig (sonst kollidiert die zweite mit dem systemd-Dienst in der
Datenbank), und auf Zeichen achten, die falsch aussehen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 22:31:41 +02:00
RichardandClaude Opus 5 f13679fadd DataGrid-Theme eingebunden - ohne es rendert kein einziges DataGrid
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
Befund B-10 aus dem Linux-Sichttest: Saemtliche Tabellen der Anwendung waren
leer - keine Zeilen, keine Spaltenkoepfe, nur eine leere Flaeche. Betroffen
waren alle DataGrids: Master-Trader, Offene/Geschlossene Trades,
Account-Uebersicht, Ledger, Jobs.

Ursache: Avalonia.Controls.DataGrid liegt in einem eigenen Paket und bringt sein
Theme NICHT ueber FluentTheme mit. In App.axaml fehlte der noetige
StyleInclude auf avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml.

Warum das so lange unbemerkt blieb: Es gibt weder eine Fehlermeldung noch eine
Bindungswarnung. Die Konstruktionspruefung bleibt gruen, weil das Fenster ja
aufgebaut wird - nur gerendert wird nichts. Und die Abnahme mit echten Daten
(A5) stand noch aus, ohne die eine leere Tabelle wie fehlende Daten aussieht
statt wie ein Fehler. Der Fehler ist NICHT linuxspezifisch, er bestand unter
Windows genauso.

Die vorhandenen Anpassungen fuer DataGrid und DataGridColumnHeader in App.axaml
bauen auf diesem Basis-Theme auf und liefen bisher ins Leere.

Build gruen, 476 Tests gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 22:27:24 +02:00
RichardandClaude Opus 5 416a804fe3 Sichtpruefung der Oberflaeche unter Linux (Teil 1 von 2)
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
Durchgefuehrt ohne Bildschirm: Anwendung unter Xvfb, Navigation per xdotool,
Aufnahmen mit import. Damit ist die Sichtpruefung reproduzierbar und ohne
Anwesenheit moeglich.

Positiv: Schriftrendering sauber inklusive Umlauten, typografischen
Anfuehrungszeichen, Emoji und Monospace im Terminal - unter Linux mit Fontconfig
nicht selbstverstaendlich. LiveCharts2/Skia rendert. Layout ohne Ueberlappungen
oder abgeschnittene Texte. Die beim Fruehjahrsputz nach Assets/ verschobenen
PNG-Symbole werden korrekt angezeigt.

Vier neue Befunde:
- B-5: Mullvad CLI Path steht unter Linux auf C:\Program Files\... - der
  Standardwert stammt aus der Windows-Zeit. Wer die VPN-Rotation einschaltet,
  bekommt einen Fehler ohne erkennbare Ursache.
- B-6: Textkontrast in den KPI-Kacheln nur 2,33:1 (gemessen, RGB 46/104/68 auf
  35/37/39). WCAG AA verlangt 4,5:1.
- B-7: Gesamt erscheint doppelt in der KPI-Kachel.
- B-8: Datumsachse der Equity-Kurve zeigt zwoelfmal 01.01. statt fortlaufender
  Daten. Vermutlich nicht Linux-spezifisch, nur hier aufgefallen.

Offen: die vier Modulfenster. Ohne Lizenzschluessel deaktiviert BuildHost alle
Module, sie bleiben in der Seitenleiste ausgegraut. Das Deploymentcenter ist von
der VM erreichbar und die Lizenz-CLI meldet bereits eine HWID auf Basis der
Linux-machine-id - eine Aktivierung waere zugleich die Live-Abnahme von D-2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 22:18:56 +02:00
RichardandClaude Opus 5 83d49aa106 A4a vollstaendig: PolyTrader laeuft als Dienst auf Linux; Testumgebung dokumentiert
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
Der Pruefplan ist abgearbeitet. Die Anwendung laeuft nicht nur, sie arbeitet:
Core-Hydration, MarketSyncService und 100 echte Maerkte von der Polymarket-API
in die Datenbank geschrieben - HTTP, TLS, JSON und DB-Zugriff funktionieren
unter Linux.

Ergebnisse im Einzelnen:
- MariaDB 11.8.6 auf der Test-VM, genau die in DatabaseServerVersion gepinnte
  Version. Alle fuenf DbContexts migriert, 21 Tabellen.
- systemd: active, Shutdown in 0,08 s (Grenze 45 s) ohne SIGKILL,
  Restart=on-failure greift nach kill -9.
- Der neue Exit-78-Schutz wirkt nachweislich: Verbindung entfernt -> Status
  failed, systemd meldet 78/CONFIG, KEINE Neustartschleife, verstaendliche
  Meldung im Journal.
- D-11 (WorkingDirectory-Falle) ist KEIN Problem: server_settings.xml wird aus
  /opt/polytrader gelesen, eine Suche ueber das ganze Dateisystem findet keine
  zweite Datei. Nebenbefund: die Datei wird beim Start gar nicht angelegt,
  erst beim Speichern von Einstellungen.
- Logrotate mit copytruncate rotiert beide Namensmuster, Dienst schreibt weiter.
- Alle neun Views konstruieren fehlerfrei, beide Farbschemata vollstaendig.

T2 ist belegt statt behauptet: Unter UTC meldet die Anwendung "Anzeige-Zeitzone:
Europe/Berlin" und stempelt in derselben Zeile mit 20:04 statt 22:04. Auf einem
UTC-Server zeigen damit alle Logs die falsche Zeit, zwischen Mitternacht und
2 Uhr sogar das falsche Datum.

Neuer Befund B-4: --smoke-ui scheitert ohne X-Server (XOpenDisplay failed),
obwohl es als CI-Werkzeug gedacht ist. "xvfb-run -a" loest es nachweislich -
relevant, sobald A2 wieder aufgenommen wird.

docs/TESTUMGEBUNG-Linux-VM.md neu: Anleitung fuer ALLE Projekte, die auf der VM
testen. Zugang per eigenem SSH-Schluessel je Projekt, eigene Datenbank je
Projekt (<projekt>_test samt eigenem Benutzer, nie eine fremde mitbenutzen),
eigenes Dienstkonto, Verzeichnis- und Portkonventionen, Belegungsliste und
Aufraeumbefehle. Kopie liegt auf der VM unter ~/TESTUMGEBUNG.md, wo jeder Agent
sie beim Verbinden findet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 22:09:09 +02:00
RichardandClaude Opus 5 4e9d7259c0 Befundbericht zum ersten Linux-Lauf
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
PolyTrader laeuft auf Linux: Build 0 Fehler, 476 Tests gruen, Publish und Start
funktionieren - bei Build und Tests kein einziger Unterschied zu Windows.

Bestaetigt: --headless braucht keine nativen GUI-Bibliotheken (BuildAvaloniaApp
wird nie aufgerufen, Skia nie geladen), master.key bekommt unter Linux korrekt
0600, Zeitzone und Lizenz-Gate verhalten sich wie dokumentiert.

Drei Befunde festgehalten: B-1 (Absturz ohne Datenbank) ist behoben, B-2
(zwei Datumsformate in Logdateinamen) und B-3 (--smoke-ui verlangt jetzt eine
Datenbank; war vorher genauso, nur unsichtbar) sind offen und beschrieben.

Nicht geprueft und warum: systemd, Oberflaeche, SIGTERM und der T2-Nachweis
brauchen eine Testdatenbank und sudo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 21:48:59 +02:00
RichardandClaude Opus 5 ad94f8c373 Verstaendlicher Abbruch statt Absturz, wenn die Datenbankverbindung fehlt
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
Erster Befund aus dem Linux-Lauf auf der Test-VM (Roadmap A4a): Ohne
konfigurierte Datenbank startete die Anwendung los und starb erst tief im
DI-Aufbau mit einer unbehandelten ArgumentException und rund 50 Zeilen
Stacktrace - "The string argument 'connectionString' cannot be empty", geworfen
aus dem EF-Kern. Exitcode 134 (SIGABRT).

Fuer den Serverbetrieb ist das gleich doppelt schlecht: Der Betreiber sieht
nicht, was fehlt, und systemd startet den Dienst wegen Restart=on-failure alle
zehn Sekunden neu. Im Journal stehen dann endlose Startversuche statt der
Ursache. Genau dieser Zustand ist bei einer Erstinstallation der wahrscheinlichste
- Software liegt da, Zugangsdaten sind noch nicht gesetzt.

Behoben an drei Stellen:
- Program.Main prueft die Verbindung, bevor der Host gebaut wird, und gibt aus,
  welcher Schluessel in welcher Datei erwartet wird, samt Beispiel und dem
  Hinweis, dass das Schema per "dotnet ef database update" angelegt wird (die
  Anwendung migriert nicht selbst).
- Rueckgabewert 78 (EX_CONFIG aus den BSD-sysexits) statt eines Absturzes.
- deploy/polytrader.service traegt RestartPreventExitStatus=78 - ein
  Konfigurationsfehler repariert sich durch Neustarts nicht, er wird dadurch nur
  unsichtbar.
- AddCorePersistence wirft als zweite Verteidigungslinie eine
  InvalidOperationException mit derselben Aussage, falls jemand die Methode
  direkt aufruft.

Der Connection-String wird dabei ueber dieselben Dateien und denselben Schluessel
gelesen wie spaeter im Host, damit beide Wege nicht auseinanderlaufen koennen.

Build gruen, 476 Tests gruen (Windows und Linux).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 21:46:45 +02:00
RichardandClaude Opus 5 e60dffbdf6 Rider-Konfiguration wieder aus dem Repo nehmen
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
Mit dem vorigen Commit sind versehentlich vier .idea/-Dateien mitgegangen
(git add -A). Sie enthalten maschinenspezifische Pfade und Index-Layouts und
blockierten den git pull auf der Linux-Testmaschine, wo Rider dieselben Dateien
lokal angelegt hat.

Die Projektkonvention ignoriert IDE-Dateien ohnehin (.vs/, *.user) - .idea/
fehlte dort nur, weil bisher niemand mit Rider gearbeitet hat.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 21:41:25 +02:00
RichardandClaude Opus 5 e9c9967ac2 Pruefplan: Durchfuehrung per SSH statt auf der VM
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
Claude Code direkt auf der Ubuntu-VM auszufuehren scheidet aus - es blockiert
die Maschine bis zum Neustart, mehrere Reparaturversuche waren erfolglos.
Der Test laeuft daher ueber SSH von der Entwicklungsmaschine aus.

Die Pruefschritte bleiben unveraendert; nur fuehrt sie nicht Richard von Hand
aus, sondern ich per SSH. Vermerkt ist auch, wo Richard trotzdem gebraucht wird:
bei allem, was Zugangsdaten oder sudo braucht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 21:13:25 +02:00
RichardandClaude Opus 5 e14dd25979 Pruefplan fuer den ersten Linux-Lauf (A4a)
CI / Build & Tests (Linux) (push) Canceled after 0s
CI / Plattformneutralität & Hygiene (push) Canceled after 0s
docs/pruefplaene/PRUEFPLAN-Linux-Betrieb.md: Schritt-fuer-Schritt-Protokoll zum
Abarbeiten auf einer Test-VM, jeder Schritt mit erwartetem Ergebnis und der
Angabe, was zurueckzumelden ist.

Zwei Fallen vorab, die beim Vorbereiten aufgefallen sind:

1. Der Linux-Publish enthaelt appsettings.Local.json mit den echten
   MySQL-Zugangsdaten. Ungeprueft auf die VM kopiert, laeuft der Test gegen die
   PRODUKTIVdatenbank - und der MarketSyncService schreibt dort als
   Hintergrunddienst hinein. Der Plan legt deshalb zuerst eine eigene
   Testdatenbank samt eigenem Benutzer an; das Umstellen der Verbindung ist
   ausdruecklich als wichtigster Schritt markiert.
2. Es gibt keine automatischen Migrationen beim Start (nachgeprueft: kein
   Migrate()/EnsureCreated() im Code). Das Schema muss vorher stehen - fuenf
   DbContexts, jeder mit eigenen Migrationen, ueber die Umgebungsvariable
   POLYTRADER_MYSQL.

Inhaltliche Schwerpunkte des Plans:
- Die Hypothese, dass --headless OHNE GUI-Bibliotheken auskommt, weil
  BuildAvaloniaApp() dort nie aufgerufen wird und Skia damit nie geladen wird.
  Der Plan prueft das bewusst zuerst ohne die Pakete - das Ergebnis entscheidet,
  was spaeter ins Server-Grundimage muss.
- Die WorkingDirectory-Falle aus D-11: server_settings.xml relativ zum
  Arbeitsverzeichnis, master.key relativ zur Programmdatei. Bei Abweichung legt
  ServerSettings.Load() kommentarlos eine neue Datei an. Wird per find ueber
  frisch geaenderte Dateien nachgewiesen.
- SIGTERM-Shutdown gegen TimeoutStopSec=45 gemessen, Restart=on-failure
  per pkill -9 gegengetestet.
- T2 (TerminalLogger stempelt DateTime.Now statt AppTimeZone) wird auf einer
  UTC-VM erstmals nachweisbar statt nur behauptet.
- Logrotate mit copytruncate, weil die App die Logdatei offen haelt.
- Master-Key als Umgebungsvariable im Dienst: erster echter Lauf von
  FilePermissions unter Linux-Rechten.

Am Ende eine Liste der zehn zurueckzumeldenden Ausgaben und die Befehle zum
Aufraeumen der VM.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 22:33:00 +02:00
RichardandClaude Opus 5 636713b573 Roadmap: CI-Runner pausiert, Linux-Test von der Zielland-Abnahme getrennt
A2 (CI-Runner) auf pausiert: auf der Gitea-Maschine ist derzeit keine Leistung
fuer einen weiteren Container frei (Entscheidung Richard). Der Workflow bleibt
liegen und ist sofort lauffaehig, sobald ein Runner da ist.

A4 aufgeteilt, weil die bisherige Blockade nicht stimmte:

- A4a "Linux-Betrieb auf einer Test-VM" ist NICHT durch A3 blockiert. Am Code
  nachgeprueft: LicenseGate ruft bei fehlender Lizenz kein Environment.Exit auf,
  sondern startet die Core-Shell im eingeschraenkten Modus ohne Trading-Module.
  Watchdog, Error-Reporting und Update-Pruefung stehen in appsettings.json
  ohnehin auf false. Der Linux-Betrieb ist damit ohne Deploymentcenter testbar -
  und Richard hat dafuer Test-VMs.
- A4b "Feldtest im Zielland" bleibt blockiert (A3 + A4a).
- A5 und B3 haengen jetzt praeziser an A4b statt an "A4".

Das ist mehr als Umsortieren: Die Anwendung ist noch nie auf Linux GELAUFEN -
verifiziert war bisher nur, dass sie sich publishen laesst. Das ist die groesste
ungetestete Flaeche im Projekt, und sie ist ab sofort adressierbar.

A4a listet konkret, was zu pruefen ist: native Abhaengigkeiten von
SkiaSharp/HarfBuzz, DB-Verhalten mit und ohne erreichbare MySQL, die
WorkingDirectory-Falle aus D-11 (server_settings.xml relativ zum
Arbeitsverzeichnis, master.key relativ zur Programmdatei - bei Abweichung legt
ServerSettings.Load() kommentarlos eine neue Datei an), SIGTERM-Shutdown,
Logrotate und der Master-Key als Umgebungsvariable unter Linux-Rechten.

Nebenbei wird dort T2 nachweisbar: der TerminalLogger stempelt mit DateTime.Now
statt AppTimeZone - auf einer UTC-VM mit Anzeigezone Europe/Berlin muessen die
Logdatei-Grenzen sichtbar von der angezeigten Uhrzeit abweichen. Bisher ist das
ein theoretischer Befund.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 21:07:08 +02:00
RichardandClaude Opus 5 6218a04fe4 Eine Roadmap statt fuenfzehn Plandokumente; Altbestand ins Archiv
Der Status des Projekts stand verstreut in elf Umsetzungsplaenen, drei
Konzepten, der Linux-Analyse und dem Projektstand - teils widersprechend, teils
wochenlang veraltet. Ab jetzt gibt es genau eine Statusquelle.

docs/ROADMAP.md (neu):
- Alle Vorhaben in vier Stufen A bis D, plus technische Schuld und Verlauf.
  Die Stufen sind eine Reihenfolge, keine Termine: jede schafft die
  Voraussetzung fuer die naechste.
- Statuszeichen: erledigt / offen / blockiert (mit Ursache) / bewusst
  zurueckgestellt / Idee, nicht beschlossen. Damit ist das, was wir NICHT bauen
  wollen, sichtbar vorgehalten statt unauffindbar in einem Plan zu schlummern.
- Inhaltlich getragen, nicht nur verlinkt: je Vorhaben Ziel, Phasen,
  Akzeptanzkriterien, offene Entscheidungen und Leitplanken aus den Quelldokumenten.
- Sichtbar gemacht, was vorher zwischen den Dokumenten verborgen lag:
  CopyTrading Phase 1 ist der Engpass der gesamten Roadmap (MarketMaking und
  BundleArbitrage haben harte Voraussetzungen darauf), und die Sniper-Metriken
  aus Phase 3.2 sind ein Spezialfall des StrategieDrift-Fingerprints - zusammen
  bauen statt doppelt.

Archiv (docs/archiv/):
- 15 Dokumente verschoben (11 Umsetzungsplaene, 3 Konzepte, ANALYSE-Linux-Portierung).
  Sie bleiben die Bauanleitungen mit Code-Bezuegen, Risikotabellen und
  Begruendungen - eingefroren ist nur ihr Status.
- archiv/README.md ordnet jedes Dokument seinem Roadmap-Punkt zu.

Verweise nachgezogen - der eigentliche Aufwand:
- 25 Markdown-Links repariert. 15 davon verschiebungsbedingt (eine Ebene
  tiefer), der Rest war schon vorher falsch: die Ideensammlung verlinkte
  Quellcode relativ zum Repo-Wurzelverzeichnis statt zu docs/.
- 12 Dateien ausserhalb von docs/ verwiesen in Kommentaren auf die Plaene
  (csproj, props, setup.json, sechs Quelldateien) - alle auf archiv/ umgebogen.
- Verweise auf Dateien, die der Fruehjahrsputz geloescht hat (Ui/,
  Program.cs, WindowMenuBar), zu Klartext entschaerft statt tote Links zu lassen.
- Gegenprobe: 85 Links geprueft, 0 kaputt. Build gruen, 476 Tests gruen.

PROJEKTSTAND.md entdoppelt: Abschnitt "Offen" verweist jetzt auf die Roadmap.
Arbeitsteilung ist damit klar - Projektstand sagt was IST, Roadmap was KOMMT.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 18:56:50 +02:00
RichardandClaude Opus 5 5507db3e32 CI fuer Gitea Actions: Build und Tests auf Linux plus Waechter gegen Rueckfaelle
Die Plattformneutralitaet war nach dem WinForms-Ausbau eine Momentaufnahme: eine
einzige net10.0-windows-Zeile oder ein "using System.Drawing" genuegt, und der
Linux-Build ist kaputt, ohne dass es auf einer Windows-Maschine auffaellt - dort
baut es weiter. Genau das faengt die CI ab, und zwar auf Linux.

.gitea/workflows/ci.yml, zwei Jobs auf ubuntu-latest:

- build-test: restore, build, die 476 Tests (brauchen keine DB, laufen gegen
  EF-InMemory), Linux-Publish. Der Publish ist kein Selbstzweck - dort faellt
  auf, wenn ein Paket doch windows-only ist. Anschliessend wird geprueft, dass
  die Executable, appsettings.json, setup.json und libSkiaSharp.so wirklich im
  Ergebnis liegen.
- guard: keine windows-TFMs, kein UseWindowsForms/UseWPF, keine windows-only
  using-Direktiven, keine versionierten Secret-Dateien, keine anfaelligen Pakete.

Alle Waechter sind in beide Richtungen gegengeprueft: sie schlagen bei
simulierten Regressionen an (windows-TFM, UseWindowsForms, using System.Drawing,
getrackte packager.config.json samt dc_sub_-Token, Newtonsoft 11.0.2) und
schweigen beim Ist-Zustand. Die Namespace-Pruefung trifft bewusst nur echte
using-Direktiven: im Bestand steht an vielen Stellen erklaert, WARUM
System.Drawing nicht verwendet wird, und das darf keinen Fehlalarm ausloesen.

Der Schwachstellen-Check ist Punkt 1 der wiederkehrenden Audit-Checkliste aus
dem Sicherheitskonzept - laeuft ab jetzt bei jedem Push statt quartalsweise von
Hand. Er wuerde zum Beispiel anschlagen, wenn der Newtonsoft-Pin im Core faellt.

Bewusst kein -warnaserror: die 15 vorhandenen Warnungen muessten erst weg, sonst
ist die CI ab dem ersten Tag rot und wird ignoriert.

WICHTIG - die CI laeuft noch nicht: auf der Gitea-Instanz ist kein Actions-Runner
registriert (auf Repo-, Benutzer- und Instanzebene geprueft, ueberall 0).
has_actions ist true, es fehlt nur der Runner. Einrichtung Schritt fuer Schritt
in docs/LEITFADEN-CI.md Abschnitt 3.

.gitattributes neu: erzwingt LF fuer .yml/.sh/.service. Entwickelt wird mit
autocrlf=true auf Windows, ausgefuehrt auf Linux - ein Shell-Skript mit CRLF
scheitert dort mit irrefuehrenden Meldungen. Bisher gab es keine .gitattributes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 11:25:01 +02:00
RichardandClaude Opus 5 1fd3671b42 Projektstand dokumentiert; Modularisierungsplan auf den Iststand nachgezogen
docs/PROJEKTSTAND.md neu: Einstiegsdokument mit Gesamtueberblick - Architektur,
Modul-Stand, was abgeschlossen ist und was offen. Alle Angaben am Code
nachgeprueft, nicht aus den Plandokumenten uebernommen. Die offenen Punkte sind
danach getrennt, ob sie am Schreibtisch erledigt werden koennen oder echtes
Geld/den Zielserver brauchen - das war vorher nirgends zusammengefasst.

Modularisierungsplan korrigiert: Die Phasen 3 bis 6 standen auf "IN ARBEIT"
beziehungsweise offen, obwohl die Arbeit seit Wochen getan war. Nachgeprueft und
abgehakt sind unter anderem:
- Phase 5: alle Modul-Services liegen im Modulprojekt, frm_main ist weg, alle
  vier Module implementieren IPolyTraderModule
- Phase 6: komplett - kein MongoDB.Driver/LiteDB mehr in irgendeiner csproj
- Phase 7 teilweise: 476 Tests, keine leeren catch-Bloecke mehr,
  Secrets-Verschluesselung umgesetzt (AES-GCM statt DPAPI, da DPAPI Windows-only
  ist und die Linux-Portierung blockiert haette)
Offen bleiben aus Phase 7 nur God-Methoden und die TerminalLogger-Umstellung.

Beim Nachpruefen aufgefallen: Accounting A-3 (US-Steuerschicht, Form 8949) ist
entgegen der bisherigen Annahme nicht gebaut - es gibt keinen UsTaxEngine.
A-2 und A-4 dagegen sind da. Im Projektstand vermerkt.

docs/README.md verweist jetzt auf den Projektstand und fuehrt die bisher
fehlenden Ordner sicherheit/ und den Deploymentcenter-Plan auf.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 11:04:02 +02:00
RichardandClaude Opus 5 bf8048b82a Fruehjahrsputz: WinForms ausgebaut (P11/L5), LicenseLabrador abgeloest (D-6)
Das Repo enthaelt ab jetzt ausschliesslich plattformneutralen Code. Build gruen
(0 Fehler), 476 Tests gruen, Linux-Publish der Avalonia-App verifiziert.
Rueckfallebene ist der Tag winforms-final, der jetzt auch auf dem Server liegt.

WinForms endgueltig ausgebaut (P11/L5):
- PolyTrader.App.csproj aus PolyTraderSharp.sln genommen und geloescht
- Ui/, Models/, Licensing/, services/, Properties/, Resources/icons/,
  Program.cs, favicon.ico entfernt - rund 4.500 LOC generierter Designer-Code
- Root-appsettings.json entfernt: exaktes Duplikat der Avalonia-Kopie, die die
  App tatsaechlich liest. Zwei Dateien mit gleichem Inhalt laufen frueher oder
  spaeter auseinander.
- Kein net10.0-windows mehr im Repo; Build-Warnungen von 23 auf 15 gesunken
  (die CS0169 aus den Designer-Resten sind weg)

PNG-Symbole gerettet statt geloescht:
Die Avalonia-App band sie per ..\..\Resources\*.png aus dem Repo-Root ein und
haette sie mitverloren. Sie liegen jetzt in src/PolyTrader.App.Avalonia/Assets/,
wo sie hingehoeren. Der avares-Pfad "Assets/<datei>.png" bleibt unveraendert -
in der gebauten Assembly nachgeprueft.

LicenseLabrador abgeloest (D-6):
- LicenseLabrador.Client aus lib/nuget entfernt, Quellen-Mapping in
  NuGet.Config auf Deploymentcenter.* reduziert, lib/nuget/README.md neu
- Bewusste Abweichung vom Plan: die Watchdog*-Felder in ServerSettings bleiben.
  D-1 hat sie auf die Deploymentcenter-API umgewidmet statt sie zu ersetzen;
  sie werden aktiv benutzt. Die Planzeile stammte aus der Zeit davor.

Weitere Altlasten:
- agentspace/ (30 Dateien: WinForms-Designer-Patcher, fix_mongo.py nach der
  MySQL-Migration, tmp/test/scratch-Skripte) entfernt
- Ideen-fuer-Mittwoch.txt entfernt - Inhalt ist laengst umgesetzt
- tote .gitignore-Regel fuer agentspace/antigravity/ entfernt
- lokal entfernt (nicht versioniert): MongoDB/-Exporte, data.db, .bak-Datei

Dokumentation nachgezogen:
- ANALYSE-Linux-Portierung.md auf Revision 6, P11/L5 als erledigt
- LEITFADEN: Abschnitt B vollstaendig aufgeloest, A5 prueft ab jetzt gegen
  einen Worktree des Tags statt gegen den Arbeitsbaum
- UMSETZUNGSPLAN-Watchdog-LicenseLabrador-Integration.md als ABGELOEST
  gekennzeichnet, D-6 im Deploymentcenter-Plan auf den Iststand gezogen

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 10:58:43 +02:00
RichardandClaude Opus 5 dd8da3fd3f Arbeitsstand gesichert: Deploymentcenter-Integration (D-0 bis D-5) und Einfenster-Shell
Sicherungscommit vor dem Aufraeumen des Repos, damit nachvollziehbar bleibt,
welcher Stand vor der Bereinigung galt. Build gruen, 476 Tests gruen.

Zwei Straenge, die sich ueber .csproj, Program.cs und appsettings.json
ueberschneiden und darum gemeinsam abgelegt werden:

Deploymentcenter-Integration (P3c, Plan D-0 bis D-5 code-seitig fertig):
- Deploymentcenter.Client 2.5.0 als lokales Paket, Source-Mapping erweitert
- DeploymentcenterOptions, DeploymentcenterErrorReporter, LicenseGate/LicenseCli
- WatchdogHeartbeatService auf die Deploymentcenter-API umgestellt
  (version, os, checks, metrics, status stopped)
- Security: MasterKeyResolver, SecretRedactor, FilePermissions
- Directory.Build.props mit zentraler Version 0.1.0 (Packager-Versionsdisziplin)
- deploy/: Packager-Vorlage und systemd-Unit; echte Zugangsdaten bleiben
  ueber .gitignore aussen vor
- setup.json fuer die Erstinstallation
- UMSETZUNGSPLAN-Deploymentcenter-Integration.md; ANALYSE-Linux-Portierung.md
  verweist auf den neuen Plan

Einfenster-Shell (UI-Redesign):
- ShellWindow + ShellNavModel als Seitenleisten-Shell
- WindowMenuBar und WindowMenuModel entfallen
- Modul- und Kernfenster auf die Shell-Einbettung angepasst

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 10:42:22 +02:00
RichardandClaude Opus 5 ac5e16f0a6 Plandokumente auf den tatsaechlichen Codestand gezogen
Beide Portierungsdokumente hingen dem Code hinterher. Commit 7f0b05e setzte A1
bis A4 um, ohne eine einzige Markdown-Datei mitzuziehen - der Leitfaden wies die
vier Punkte weiter als offen aus. Ein Agent, der ihn als Arbeitsanweisung nimmt,
haette sie ein zweites Mal gebaut.

LEITFADEN-Avalonia-Portierung.md:
- A1 bis A4 als erledigt markiert, mit Ist-Tabelle: wo der Code liegt und dass
  auch die Feinheiten sitzen (nullables GetService fuer Supervisor, LaunchUriAsync
  statt Process.Start, DialogWindow.Confirm vor Delete, ContextMenu mit beiden
  Eintraegen). Die Soll-Beschreibungen bleiben als Pruefvorlage fuer A5 stehen.
- A5 (Durchsehen mit echten Daten) als einziger offener Punkt ausgewiesen.
- Abschnitt B um das Lizenz-Gate und den Watchdog-Heartbeat ergaenzt. Wichtig fuer
  den Naechsten: die Avalonia-App setzt derzeit GAR KEINE Lizenz durch, waehrend
  die WinForms-Fassung das Gate weiter hat. Beides kommt mit dem Deploymentcenter
  neu, also dort nichts mehr investieren.
- Neuer Abschnitt C fuer Folgepunkte ohne Blockerwirkung.

ANALYSE-Linux-Portierung.md (Revision 5):
- P5 bis P8 als erledigt, Stufen L3 und L4 entsprechend; Restaufwand von 33-51 PT
  auf 7-13 PT korrigiert.
- Offen bleiben P3c (Deploymentcenter, steht als Naechstes), CI, systemd/Feldtest,
  WinForms-Ausbau und die Abnahme A5.
- Historische Aufwandszahlen als Rueckblick gekennzeichnet statt geloescht.

Nachgeprueft statt uebernommen: A1-A4 gegen den Code verifiziert, ebenso dass es
keinerlei CI-Konfiguration gibt (weder .github noch .gitea) und dass --headless in
App.Avalonia/Program.cs bereits existiert.

Beim Pruefen aufgefallen, kein Fehler: TerminalLogger schreibt die Tagesdatei mit
DateTime.Now und der Launcher liest sie mit DateTime.Now - konsistent, aber beide
ignorieren die in P2 eingefuehrte AppTimeZone. Als Folgepunkt C notiert, relevant
erst beim Headless-Betrieb auf einem UTC-Server.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 21:59:10 +02:00
RichardandAntigravity AI 7f0b05e9ba Avalonia-Portierung verbleibender UI-Elemente (A1 bis A4) umgesetzt
Paritaet mit dem WinForms-Referenzstand (Tag winforms-final) hergestellt:

- A1 & A2 (Launcher): Account-Uebersicht DataGrid (inkl. Polymarket-Profil-Button via Launcher.LaunchUriAsync), Modul-KPI-Kacheln (7T/30T PnL & Winrate) und 3-Spalten-Live-Ueberblick (Auffaellige Trades 24h, Warnungen & Fehler heute aus den JSONL-Logs, Supervisor-KI Bericht). Periodische Aktualisierung alle 30 s eingebaut.
- A3 (Copytrading): Master-Trader Werkzeugleiste um 'Neu' (AddNewTrader) und 'Loeschen' (DeleteSelectedTrader mit DialogWindow.Confirm) erweitert.
- A4 (Terminal): Log-Kontextmenue fuer 'Kopieren' und 'Alles auswaehlen' an die Live-Log-Ausgabe angefuegt.

Verifiziert: Solution baut fehlerfrei, 450 Tests gruen, --smoke-ui test erfolgreich.

Co-Authored-By: Antigravity AI <antigravity@google.com>
2026-08-10 10:48:27 +02:00
RichardandClaude Opus 5 29ea62fc7f Portierungsleitfaden fuer die Fortsetzung der Avalonia-Umstellung
docs/LEITFADEN-Avalonia-Portierung.md: Anleitung fuer einen KI-Agenten, der die UI-
Portierung weiterfuehrt. Enthaelt bewusst eine EHRLICHE Luecken-Liste - alle acht Fenster
konstruieren zwar, mehrere sind aber inhaltlich unvollstaendig. Gegen den Tag
winforms-final verglichen und belegt:

- A1: Launcher-Live-Ueberblick fehlt KOMPLETT (auffaellige Trades 24h, Warnungen/Fehler
  heute aus der JSONL, letzter Supervisor-Bericht, Modul-KPIs) - groesste Luecke
- A2: Launcher-Account-Uebersicht fehlt KOMPLETT (inkl. Polymarket-Button je Konto)
- A3: Copytrading, Master-Trader: 'Neu' und 'Loeschen' nicht verdrahtet
- A4: Terminal-Kontextmenue (Kopieren/Alles auswaehlen) fehlt
- A5: kein Fenster wurde mit echten Daten durchgeklickt - Spaltenbreiten, Umbrueche und
  Splitter-Positionen sind ungeprueft

Dazu die Regeln (Layout deklarativ, keine festen Farben, keine Erfolgs-Dialoge, Module
bleiben frei von Avalonia), das Baukastenmuster, die Stolperfallen die mich Zeit gekostet
haben (x:DataType, CalendarDatePicker-Typ, BindingList vs ObservableCollection,
LoadingRow, Namenskollision ClosedTradeRow, SaveFilePicker-Pfad), die Pruefbefehle mit
erwarteter Ausgabe und was NICHT angefasst werden darf (Avalonia 12, Lizenzdialog,
WinForms-Projekt).

Alle Dateiverweise und der dokumentierte Smoke-Befehl sind verifiziert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 08:34:54 +02:00
RichardandClaude Opus 5 487ea4466d Dunkelmodus mit Umschalter in der Fensterleiste
Farbschema hell / dunkel / dem System folgen, umschaltbar per Klick, Stand wird in
server_settings.xml gemerkt (ServerSettings.Theme). Der Editor zeigt die Einstellung
automatisch als Auswahlfeld - kein Zusatzcode, weil sie ein Enum ist.

- App.axaml: 18 Farb-Token je Variante (Flaechen, Rahmen, Texte, Bedeutungsfarben,
  Zeilenfaerbung, Trading-Umschalter, Chat-Rollen). Die Standard-Steuerelemente stellt
  das FluentTheme selbst um.
- 22 fest verdrahtete Farben in 11 XAML-Dateien auf DynamicResource umgestellt - die
  wechseln damit von selbst mit.
- Umschalter (Sonne/Mond) sitzt in der gemeinsamen Fensterleiste, also auf JEDEM Fenster.

Der eigentliche Knackpunkt waren die Farben, die im Code gesetzt werden - die folgen dem
Thema NICHT von selbst:
- TradeRowPalette liefert jetzt Eigenschaften statt static readonly, loest also bei jedem
  Zugriff neu auf. Im Dunkeln gedaempfte Toene statt der hellen Pastelltoene, die dort
  blenden und den Text unlesbar machen wuerden.
- ChatEntry speichert die ROLLE statt eines fertigen Brush - dadurch stimmt der Verlauf
  nach dem Umschalten ohne Neuaufbau der Liste.
- Launcher-Umschalter, Dashboard-KPI und die Grid-Zeilenfarben zeichnen sich ueber
  ThemeManager.ThemeChanged neu.
- Das Terminal bleibt in beiden Schemata dunkel (Konsolen sind konventionell dunkel).

Nebenbei die Anzeige-Kultur gepinnt (stand ohnehin auf der Linux-Liste): auf Linux richtet
sie sich sonst nach LANG/LC_ALL, das unter systemd oft nicht gesetzt ist - dann faellt .NET
auf Invariant zurueck und aus '1.234,56 USDC' wird '1,234.56 USDC'. Maschinen-I/O laeuft
davon unabhaengig weiter invariant.

Smoke-UI prueft jetzt zusaetzlich, dass ALLE 18 Farben in BEIDEN Varianten aufloesen -
ein vertippter Ressourcenschluessel wuerde sonst still grau werden.

Verifiziert: Solution baut, 450 Tests gruen, --smoke-ui gruen (10 Fenster + Editor +
beide Farbschemata), App startet im gespeicherten Schema, Linux-Publish laeuft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 22:41:25 +02:00
RichardandClaude Opus 5 669676ac60 Modul-Fenster nach Avalonia - UI-Portierung inhaltlich abgeschlossen
Alle acht Fenster laufen jetzt unter Avalonia: Launcher, Dashboard, Settings, Terminal,
Server Jobs, Copytrading, ResolutionFarming, Supervisor, Accounting (+ Shutdown- und
Allzweck-Dialog).

- Copytrading: vier Tabs (Master-Trader mit Account-Zuweisung, Offene Trades, Geschlossene
  Trades mit Filterleiste, Account-Einstellungen). Zeilenfaerbung nach PnL laeuft ueber
  DataGrid.LoadingRow - greift damit auch bei virtualisierten Zeilen, anders als das
  fruehere Faerben in DataBindingComplete.
- ResolutionFarming: Kandidaten, Positionen, Historie, Settings - je Konto.
- Supervisor: Analyse-Chat gegen den Agenten (Tool-Fortschritt in der Statuszeile),
  Dossiers mit Markdown-Ansicht, Berichte, Counterfactuals.
- Accounting: KPI-Kacheln, Monats-BWA, Ledger, Abruf/Status, PDF- und CSV-Export ueber
  den plattformneutralen Datei-Dialog.

Der SettingsEditor traegt wie erwartet die drei restlichen PropertyGrid-Stellen
(Master-Trader, Account-Einstellungen, ResolutionFarming) mit je einem Aufruf.

ENTSCHEIDUNG - Modul-Fenster liegen in der App, nicht in den Modulen
(begruendet in Views/Modules/README.md): Die App ist der Kompositionswurzel und
referenziert ohnehin alle Module. So bleiben die Modulprojekte FREI VON AVALONIA, was fuer
den kopflosen Linux-Betrieb den Ausschlag gibt - der Daemon soll keine GUI-Bibliothek
mitschleppen. Verifiziert: kein Modul zieht Avalonia. Registrierung in Shell/ModuleViews.cs,
und zwar nur fuer tatsaechlich geladene Module - ein per DisabledModules abgeschaltetes
Modul bekommt gar kein Fenster.

Nebenbei: eigene View-Model-Typen CopyOpenTradeRow/CopyClosedTradeRow statt des
Modul-Modells ClosedTradeRow - sie tragen den aufgeloesten Master-Trader-Namen und die
Zeilenfarbe, die es dort nicht gibt (und vermeiden die Namensmehrdeutigkeit).

Verifiziert: Solution baut, 450 Tests gruen, --smoke-ui gruen (alle 8 Fenster + Launcher +
Dialog + Editor-Pruefung), App laeuft real mit allen Trading-Diensten, Linux-Publish laeuft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 22:19:42 +02:00
RichardandClaude Opus 5 929fa20ee0 Terminal nach Avalonia + konfigurierbare Zeitzone (P2-Kern)
Alle vier Core-Fenster sind damit portiert.

TERMINAL:
- Live-Ausgabe als virtualisiertes ItemsControl ueber eine begrenzte Zeilenliste statt
  RichTextBox. Damit entfaellt das Auto-Clear der WinForms-Fassung, das bei Erreichen der
  Zeichengrenze den GESAMTEN Verlauf verwarf - jetzt werden nur die aeltesten Zeilen
  verdraengt (Ringpuffer, 5000 Zeilen), der juengste Verlauf bleibt immer sichtbar.
  Die Zeilenzahl steht in der Statuszeile.
- Log-Viewer unveraendert im Funktionsumfang: JSONL-Tagesdateien, Filter nach Datum, Level,
  CID und Volltext, Doppelklick uebernimmt die CID (Signal-Kette verfolgen).

ZEITZONE (Befund aus der Linux-Analyse, hier faellig geworden):
Die Terminal-Ansicht rechnete hart gegen die WINDOWS-ID 'W. Europe Standard Time'. Auf Linux
traegt die nur ueber die ICU-Zuordnung und faellt ganz aus, wenn ICU fehlt oder
InvariantGlobalization gesetzt ist - das Fenster haette beim Oeffnen geworfen.

Neu: PolyTraderSharp.Services.AppTimeZone + ServerSettings.ApplicationTimeZoneId
(Default 'Europe/Berlin', IANA-Schreibweise). Aufloesung versucht die ID direkt, dann die
jeweils andere Schreibweise (IANA<->Windows), zuletzt die Systemzeitzone - ein unbekannter
Wert ist damit nie fatal, sondern erzeugt nur eine Warnung. Beide Programm-Einstiege setzen
sie einmalig beim Start; laut Vorgabe wird sie bei der Installation festgelegt und nicht im
laufenden Betrieb gewechselt (Aenderung verschiebt Logdatei-Tagesgrenzen).

8 neue Tests (AppTimeZoneTests) halten fest: IANA- UND Windows-ID liefern denselben
UTC-Versatz (Winter +1, Sommer +2), unbekannte IDs fallen mit Warnung auf die Systemzeitzone
zurueck, leere Angabe = Systemzeitzone, UTC wird korrekt umgerechnet.

Verifiziert: Solution baut, 450 Tests gruen, --smoke-ui gruen (6 Fenster + Editor-Pruefung,
Zeitzone loest als Europe/Berlin auf), App laeuft real, Linux-Publish laeuft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 21:06:24 +02:00
RichardandClaude Opus 5 4ba8149e64 Settings nach Avalonia - PropertyGrid durch kategorisierten Editor ersetzt
Der PropertyGrid-Ersatz ist EIN wiederverwendbares Steuerelement statt Handarbeit je Feld:
Controls/SettingsEditor zeigt ein beliebiges Einstellungsobjekt nach Richards Vorlage -
Kategorie-Ueberschrift, Beschriftung links, Feld rechts, Erklaerung klein darunter.

- SettingsModelBuilder liest die Attribute, die fuers PropertyGrid ohnehin gepflegt waren:
  [Category] gruppiert, [DisplayName] beschriftet, [Description] wird zum Hinweistext,
  [Browsable(false)] blendet aus (Watchdog-Token, Lizenzschluessel bleiben unsichtbar).
  Ergebnis fuer ServerSettings: 6 Abschnitte, 15 Felder - ohne eine Zeile Feld-Code.
- Layout-Regel gewahrt: WELCHE Felder es gibt, kommt als Daten; WIE ein Feld aussieht,
  steht deklarativ als DataTemplate je Feldtyp (Text/Zahl/Ja-Nein/Auswahl/Nur-Lese).
- Damit sind auch die drei restlichen PropertyGrid-Stellen (Account-Einstellungen,
  Master-Trader, ResolutionFarming) mit je einem Aufruf erledigt.

SettingsWindow: Server-Settings + Polymarket-Accounts, Master-Key erzeugen,
OpenRouter-Key/Watchdog-Token setzen, Test-Heartbeat. Rueckmeldungen laufen ueber die
Statuszeile statt ueber Dialoge - nur echte Entscheidungen bekommen einen Dialog
(neu: Views/DialogWindow fuer Hinweis/Rueckfrage/maskierte Eingabe, Avalonia hat keine MessageBox).

Nebenbei einen offenen Punkt der Linux-Analyse erledigt: Schluesseldateien (master.key,
openrouter.key) werden jetzt per File.SetUnixFileMode auf 600 gesetzt. Auf Linux legt
File.WriteAllText sonst mit ueblicher umask 644 an - weltweit lesbar.

Lizenzdialog bewusst NICHT portiert: haengt am alten LicenseLabrador-SDK, das mit der
Deploymentcenter-Anbindung (P3c) ohnehin ersetzt wird - waere Wegwerfarbeit.

Smoke-UI prueft jetzt zusaetzlich die Feldzahl des Editors: ein Fenster kann fehlerfrei
konstruieren und trotzdem leer sein, wenn die Attribute verlorengehen.

Verifiziert: Solution baut, 442 Tests gruen, --smoke-ui gruen (5 Fenster + Editor-Pruefung),
Linux-Publish laeuft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 20:55:47 +02:00
RichardandClaude Opus 5 0b8728b25f Dashboard nach Avalonia portiert - LiveCharts2 laeuft
Drittes Fenster: KPI-Kacheln, drei Diagramme, Tradehistorie mit Suche/Filter und
Modul-Aktivierung. Aufbau nach docs/UI-SPEZIFIKATION-WinForms.md.

- Diagramme sind jetzt echte Steuerelemente (LiveCharts2) statt nach Bitmap gerenderter
  ScottPlot-Bilder: interaktiv (Tooltips/Zoom) und ohne System.Drawing. Die Auswertung
  kommt unveraendert aus TradeAnalytics - der Chart-Wechsel beruehrte keine Fachlogik.
  Das war der Zweck der bestehenden Trennung und hat sich hier ausgezahlt.
- ModuleActivationInfo vom UI-Typ in den Core verschoben (PolyTrader.Core.Modularity):
  Aussage ueber die Modularitaet, keine Darstellungsfrage - beide Shells brauchen sie.
- Modul-Tab listet auch NICHT geladene Module, sonst liessen sie sich nie reaktivieren.
  Blockierte Module haben eine deaktivierte Schaltflaeche statt eines Hinweisdialogs;
  der Grund steht ohnehin in der Spalte 'Hinweis'.

WICHTIG - Avalonia 12 -> 11.3.19 zurueckgenommen:
Der erste Wurf zog per Version='*' Avalonia 12.1.1. LiveCharts2 2.0.5 (die aktuellste
Version) ist gegen Avalonia 11 gebaut und bricht dort zur Laufzeit:
MissingFieldException 'Avalonia.Input.Gestures.PinchEvent'. Avalonia 12 ist dem
Chart-Oekosystem voraus. Jetzt 11.3.19 (DataGrid folgt eigener Reihe: 11.3.13).
Erst wieder anheben, wenn LiveCharts2 Avalonia 12 unterstuetzt.

Verifiziert: Solution baut, 442 Tests gruen, --smoke-ui gruen (alle 4 Fenster),
App laeuft real mit allen Trading-Diensten, publisht fuer linux-x64.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 20:45:07 +02:00
RichardandClaude Opus 5 cd59e5c0a5 Avalonia-Grundgeruest: plattformneutrale App laeuft (Shell + erstes Fenster)
Neues Projekt src/PolyTrader.App.Avalonia (net10.0, Avalonia 12.1.1, LiveCharts2 2.0.5)
- laeuft unter Windows und Linux aus derselben Quelle.

Enthalten:
- Program.cs mit bewusst getrenntem Aufbau: BuildHost() stellt Persistenz, Dienste und
  Module ohne jeden UI-Bezug zusammen, erst Main haengt Avalonia daran. Damit ist der
  kopflose Linux-Betrieb (--headless, Stufe L2) ohne Umbau erreichbar - der Schalter ist
  bereits drin.
- AvaloniaUiHost als IModuleUiHost: gleiche Semantik wie die WinForms-Shell (ein Fenster
  je View, offene nach vorn holen, alles maximiert).
- Fenster-Menueleiste vollstaendig DEKLARATIV (Controls/WindowMenuBar.axaml + ItemsSource
  auf WindowMenuModel.Entries). Loest die alte Fassung ab, die menu.Items zur Laufzeit
  leerte und neu befuellte - genau der Punkt, den die neue Layout-Regel verbietet.
- ViewIcons fuer Avalonia: dieselben Schluessel und dieselben PNGs wie zuvor, Core und
  Module bleiben unveraendert.
- LauncherWindow, JobsWindow, ShutdownConfirmWindow (inkl. der 10-Sekunden-Sperre).
- --smoke-ui als Nachfolger der WinForms-Konstruktionspruefung; startet den Host bewusst
  NICHT, damit ein reiner UI-Test nicht die Trading-Engine gegen echte Endpunkte anwirft.

Dabei aufgeraeumt:
- JobManager.Jobs: BindingList -> ObservableCollection. BindingList implementiert kein
  INotifyCollectionChanged; neu registrierte Jobs waeren in Avalonia unsichtbar geblieben.
- StartupHydrationService aufgeteilt in CoreStateHydrationService (Core: Accounts +
  Demo-Positionen) und CopyTradingHydrationService (Modul: Settings + Trader). Behebt einen
  latenten Fehler: bei deaktiviertem Copytrading-Modul waeren die Accounts gar nicht mehr
  hydriert worden, obwohl sie zum Core gehoeren.

Verifiziert: Solution baut, 442 Tests gruen, --smoke-ui gruen, die App laeuft real mit
Fenster und allen Trading-Diensten (Market-Sync, Master-Trader-Analyse, RF-Scanner),
und publisht fuer linux-x64.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 17:55:05 +02:00
RichardandClaude Opus 5 a2b1c18ee3 Umstieg auf .NET 10 + transitive Newtonsoft-Luecke geschlossen
Alle sieben Projekte auf net10.0 (App: net10.0-windows). Runtime 10.0.10 ist
installiert, 442 Tests gruen, Linux-Publish aller Nicht-App-Projekte laeuft.

EF Core 8 / Pomelo 8 bleiben bewusst stehen: net10.0 konsumiert net8.0-Bibliotheken
problemlos, und ein Provider-Wechsel hat wegen der Migrations-Implikationen eine
eigene Risikoflaeche - das gehoert in einen separaten, verifizierten Durchgang.

Sicherheitsfund nebenbei: Ab .NET 9 prueft NuGet standardmaessig auch transitive
Pakete. Damit wurde sichtbar, dass Nethereum 6.1.0 Newtonsoft.Json [11.0.2, 14.0.0)
zulaesst und ohne Pinnung auf 11.0.2 aufloest - bekannte Luecke hoher Schwere
(GHSA-5crp-9r3c-p9vr). Die App pinnte laengst 13.0.4, Core und Module nicht.
Jetzt im Core gepinnt, damit jeder Consumer sie bekommt (auch der kuenftige
Linux-Daemon). Danach 0 NU1903-Warnungen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 17:42:24 +02:00
RichardandClaude Opus 5 f8aa90882b Analyse auf Revision 4: P1/P3b/P4 als erledigt vermerkt
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 17:33:00 +02:00
RichardandClaude Opus 5 53546ceeeb P1c+P4: Module und Tests auf net8.0 - WinForms nur noch in PolyTrader.App
Variante B (Entscheidung Richard): Modul-UI entfernt statt in Zwischenprojekte
ausgelagert. Avalonia ist plattformuebergreifend, die neuen Ansichten kommen spaeter
direkt in die Modul-Projekte zurueck - kein Zwischenschritt, keine Wegwerfarbeit.

- 23 WinForms-Dateien aus den 4 Modulen entfernt (Spezifikation steht in
  docs/UI-SPEZIFIKATION-WinForms.md, Originalcode im Tag winforms-final).
- RegisterUi ist jetzt je Modul ein dokumentierter No-Op: View-ID, Titel, Gruppe,
  Order und der Tab-Aufbau stehen als XML-Doku drin, damit der Avalonia-Nachbau
  die stabilen IDs und die Struktur uebernimmt.
- Alle 4 Modulprojekte + Testprojekt: net8.0 statt net8.0-windows, UseWindowsForms raus.
- P4 vorgezogen (war durch den Testprojekt-Wechsel faellig): PDFsharp-MigraDoc-GDI
  -> PDFsharp-MigraDoc (Core-Build). Der Core-Build findet keine Systemschriften,
  daher neu Logic/PdfFontResolver.cs: durchsucht die Schriftverzeichnisse des OS nach
  Segoe UI/DejaVu/Liberation/Noto/Arial/FreeSans. Keine Schriftdateien im Repo noetig;
  fehlt auf Linux alles, kommt eine klare Meldung mit apt-Hinweis statt eines
  kryptischen Renderer-Fehlers.

Verifiziert: Core, alle 4 Module und das Testprojekt publishen fuer linux-x64, und
zwar ohne ein einziges Windows-spezifisches Paket in den deps.json. 442 Tests gruen
(inkl. PDF-Rendering) auf net8.0. Windows-App laeuft weiter mit den Core-Fenstern.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 17:32:12 +02:00
RichardandClaude Opus 5 0a26b8563d UI-Spezifikation der WinForms-Oberflaeche gesichert (Rekonstruktionsvorlage)
Vor dem Entfernen der WinForms-UI: maschinell aus allen .Designer.cs extrahierte
Spezifikation aller 16 Fenster - Groessen, Tabs, Beschriftungen, Schaltflaechen und
saemtliche Grid-Spalten mit Reihenfolge, Format und Breite. Dazu uebergreifende
Gestaltungsregeln, Farbwerte der PnL-Zeilenfaerbung, Symbol-Schluessel je Fenster
und Verhaltensnotizen aus dem Code-Behind.

Damit laesst sich die Avalonia-UI moeglichst 1:1 nachbauen. Der Originalcode bleibt
zusaetzlich im Tag winforms-final; das Dokument empfiehlt, dort einmalig Screenshots
mit echten Daten zu ziehen (optischer Gesamteindruck, den kein Text ersetzt).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 17:27:42 +02:00
RichardandClaude Opus 5 5320d25d6d P1b: System.Drawing aus der Fachlogik entfernt
- TradeRowColoring liefert jetzt eine TradeRowTint-Kategorie (Loss/SmallWin/BigWin)
  statt einer System.Drawing.Color. Die Schwellenlogik bleibt getestet, die konkrete
  Farbe legt die UI fest (neu: Ui/TradeRowPalette.cs im CopyTrading-Modul).
  Bessere Schichtung und Voraussetzung dafuer, dass das Modul spaeter net8.0 wird.
- TradeRowColoringTests prueft die Kategorie statt der Farbe (gleiche Abdeckung).
- Models/DashboardRow.cs: verwaistes using System.Drawing entfernt.

System.Drawing liegt damit ausschliesslich noch in UI-Ordnern - die Fachlogik in
Core und Modulen ist frei davon.

442 Tests gruen, --smoke-ui gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 17:13:14 +02:00
RichardandClaude Opus 5 ad1593bfc1 P1a: PolyTrader.Core auf net8.0 - UI-Contract toolkit-neutral
Der Core traegt keine WinForms-/System.Drawing-Abhaengigkeit mehr und baut als
plattformneutrales net8.0 (verifiziert: publish -r linux-x64 erfolgreich).

- ModuleView.CreateForm (Func<Form>) -> CreateView (Func<object>): die Shell kennt
  ihr Toolkit und castet, der Core nicht. Avalonia kann denselben Contract nutzen.
- ModuleView.Icon (System.Drawing.Image, seit .NET 7 Windows-only) -> IconKey (string).
  Aufloesung Schluessel->Bildressource neu in Ui/ViewIcons.cs, ersetzt Program.AssignMenuIcons.
- WindowMenu.cs (reine WinForms-Logik) aus dem Core nach Ui/ verschoben.
- WindowMenuTests entfernt: testet die eingefrorene WinForms-Menuelogik, die das
  Testprojekt nach dem Core-Schnitt nicht mehr erreicht. Im Tag winforms-final erhalten;
  das Avalonia-Gegenstueck bekommt eigene Tests (P6/P9).

Module und App bleiben vorerst net8.0-windows - ihre UI zieht erst mit der
Avalonia-Portierung um. Windows-App unveraendert lauffaehig (--smoke-ui gruen).

442 Tests gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 17:10:41 +02:00
RichardandClaude Opus 5 fd6d62618f Kultur-Bug behoben + Threema entfernt (INotificationSink)
- TraderMonitorService las API-Preise kulturabhaengig: unter de-DE wurde aus
  "0.53" der Wert 53 (Faktor-100-Fehler im Einstandspreis). Nutzt jetzt den
  bereits vorhandenen invarianten Helper ParseDecimal.
- Gleiche Fehlerklasse in PolymarketClobClient (6x) und MasterTraderAnalyticsJob
  vorsorglich auf InvariantCulture gestellt.
- Neuer Regressionstest ApiNumberParsingTests (10 Faelle unter erzwungener de-DE-Kultur).
- Threema komplett entfernt (Entscheidung Richard): ThreemaService, vendorte
  Bibliothek libs/Threema-MsgApi-Net-Core, ServerSettings-Block, DI-Verdrahtung.
- Ersetzt durch neutrale INotificationSink (No-Throw-Vertrag) + LogNotificationSink
  als Uebergang; RocketChat/Telegram folgen spaeter.
- Entfernt nebenbei libsodium 1.0.16, die einzige Registry-Nutzung im Build,
  den HttpListener-Webhook und System.Web.HttpUtility (alles Linux-Hindernisse).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 12:01:13 +02:00
RichardandClaude Opus 5 ab0a494f29 LicenseLabrador-SDK als lokales NuGet-Paket statt Cross-Repo-Projektreferenz
PolyTrader.App.csproj verwies per ProjectReference nach
..\..\LicenseLabrador\client-dotnet\... und baute damit nur auf einer
Maschine, auf der das Schwester-Repo danebenliegt. Auf dem Zielland-System
waere der Build fehlgeschlagen.

Stattdessen liegt das SDK als versioniertes Paket in lib/nuget und wird
ueber die NuGet.Config-Quelle "local" aufgeloest. Ein DLL-Verweis haette
nicht gereicht: das Paket traegt die transitiven Abhaengigkeiten
(BouncyCastle, ProtectedData, System.Text.Json) in seinen Metadaten.

packageSourceMapping bindet LicenseLabrador.* fest an den lokalen Feed,
damit ein gleichnamiges Paket auf nuget.org unseres nicht verdraengt
(Dependency Confusion).

Enthaelt ausserdem die bereits vorgemerkte Umbenennung
LicenseDialog.Validate -> ValidateKey: der alte Name verdeckte
ContainerControl.Validate() (CS0108), ein Aufruf ueber eine Form-Referenz
haette einen Netzwerk-Call ausgeloest statt zu validieren.

Build und Tests gruen (438 Tests).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 13:13:35 +02:00
RichardandClaude Opus 5 db6c37eaa4 Ideen-fuer-Mittwoch.txt als erledigte Historie aufgenommen
Die urspruengliche Ideenliste (Menueleiste, sicheres Beenden, Modul-Aktivierung,
Watchdog, ClawdDotNet) ist vollstaendig abgearbeitet - UI-Slice 5 (039bc24),
Watchdog/Lizenz (ca750a0) und die ClawdDotNet-Uebernahme (bb103a5). Die Datei
wird als Nachweis mitgefuehrt, worauf diese Slices zurueckgehen; abgeloest wird
sie von docs/IDEENSAMMLUNG-Feldtest-2026-08.md, die auf diesen Dateinamen verweist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 09:21:05 +02:00
RichardandClaude Opus 5 73ad37c5ac Ideensammlung Feldtest 2026-08 angelegt (Beobachtungen aus dem Praxiseinsatz)
Laufende Sammlung von Richards Beobachtungen beim Einsatz von PolyTrader, je Punkt
Beobachtung -> Befund (im Code geprueft) -> Ansatz, mit stabilen IDs (L-1, ACC-1 ...)
als Referenz fuer spaetere Umsetzungs-Chats. Hier wird bewusst NICHT umgesetzt.

Querschnitts-Erkenntnis: ACC-1, RF-1 und teilweise CT-3 haben dieselbe Ursache -
Module wurden mit Null-Stubs statt echter Datenquellen fertiggestellt und mit
"Zielland" zurueckgestellt. Zielland-gebunden ist aber nur das Schreiben (Orders,
Signing, On-Chain-Tx); Lesen (Data-/Gamma-API, Alchemy-Logs, Balance) ist es nicht.
Loest die abgearbeitete Liste Ideen-fuer-Mittwoch.txt ab.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 09:04:24 +02:00
RichardandClaude Opus 5 ca750a06f5 Watchdog-Heartbeat + LicenseLabrador-Lizenzpruefung eingebunden
Slices W-A/W-B/W-C und L-A aus UMSETZUNGSPLAN-Watchdog-LicenseLabrador-Integration.

Watchdog (Dead-Man's-Switch, externer Server):
- WatchdogHeartbeatService als BackgroundService + DI-Singleton; jeder Sendeversuch
  gekapselt, ein Ausfall des Watchdogs beeintraechtigt PolyTrader nie.
- Eigene Implementierung statt Test-Client des Fremdprojekts: TLS-Pruefung bleibt
  aktiv, http:// nur fuer localhost (Agent-Token nicht im Klartext ins Netz).
- Status aus dem App-Log abgeleitet (Error mit 5-Minuten-Sticky-Fenster, entprellt),
  Lifecycle-Events started/stopping.
- Konfiguration in ServerSettings; Agent-Token [Browsable(false)] mit maskierter
  Eingabe + Statusanzeige, bei gesetztem Master-Key verschluesselt (enc:v1:).

Lizenz (LicenseLabrador, Ed25519):
- LicenseGate.RunStartupGate prueft beim Start; bei ungueltiger Lizenz wird die
  Modulliste leer gebaut, sodass nur die Core-Shell (Terminal/Einstellungen)
  startet. Bewusst kein Environment.Exit - ein Trading-Bot darf nicht mitten im
  Lauf hart sterben. TamperSuspected gilt als nicht nutzbar.
- LicenseDialog (partial + .Designer.cs) fuer Start- und Verwalten-Modus, mit
  Hardware-ID zum Kopieren; Smoke-UI konstruiert beide Modi headless.
- Master-Key wird jetzt VOR dem Host-Build geladen, da auch der Lizenzschluessel
  entschluesselt werden muss; derselbe TerminalLogger wird als Singleton
  weitergereicht, damit die Startmeldungen im Terminal-Fenster erscheinen.

Der Lizenz-SDK-Client wird per Cross-Repo-Projektreferenz auf
..\..\LicenseLabrador eingebunden, damit SDK-Fixes ohne Kopie einfliessen.

484 Zeilen Tests fuer den Heartbeat; Suite gruen (438 Tests).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 09:04:14 +02:00
RichardandClaude Opus 4.8 bb103a578a Agenten-Kostendeckel: LoopGuard + PermissionGate aus ClawdDotNet uebernommen
- Neu PolyTrader.Core/Agents: AgentBudget (Steps/Tokens/Timeout), LoopGuard
  (thread-safe, AgentBudgetExceededException mit Kind), PermissionGate
  (Tool-Allow-List, null = alle erlaubt). Aus ClawdDotNet portiert, NICHT als
  Abhaengigkeit (.NET 10 vs 8).
- SupervisorAgent nutzt LoopGuard (Default-Steps = MaxIterations=8, rueckwaerts-
  kompatibel) + PermissionGate (Allow-List = angebotene Tools; nicht freigegebene
  Calls liefern Fehlertext statt Ausfuehrung). SupervisorProfile.Budget ueber-
  schreibt den Deckel. Abbruch graceful mit Grund (Steps/Tokens/Zeit).
- Tests: AgentGuardTests (LoopGuard/PermissionGate) + Token-Abbruch am Agenten.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 20:29:47 +02:00
RichardandClaude Opus 4.8 039bc240f8 UI Slice 5: Menueleiste (Fenster nebeneinander), sicheres Beenden, Modul-Aktivierung
- Fenster-Menue: WindowMenu fuellt die oberste MenuStrip mit Top-Level-Eintraegen
  nebeneinander (mit Icon) statt Untermenue "Fenster"; ModuleView.Icon zentral in der
  App zugewiesen (AssignMenuIcons). Kein miFenster mehr im Launcher-Designer.
- Sicheres Beenden: ShutdownConfirmDialog (10s-Timer sperrt "Jetzt beenden", Abbrechen
  jederzeit) via IModuleUiHost.RequestShutdown(). Nur der Launcher (Hauptprozess) bietet
  "Beenden"; andere Fenster nur "Fenster schliessen" (kein App-Shutdown, Module laufen
  weiter). Launcher-Schliessen-X routet ueber dieselbe Abfrage.
- Modul-Aktivierung (restart-basiert): ServerSettings.DisabledModules, in Program.Main
  vor der DI-Registrierung gefiltert -> deaktivierte Module werden nicht geladen.
  Dashboard-Tab "Module" zeigt Status + schaltet um (Hinweis: greift nach Neustart).
  Optionaler IPolyTraderModule.GetActivationBlocker fuer "nicht aktivierbar"-Info.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 18:46:09 +02:00
RichardandClaude Opus 4.8 886de3a85b Icon emotion_hitler entfernt (unbenutzt): resx-Eintrag, Designer-Property, PNG + ico geloescht
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 09:44:09 +02:00
RichardandClaude Opus 4.8 3c8ea3534e UI Slice 4: Launcher-Live-Widgets + VS-Re-Serialisierungs-Regressionen behoben
Slice 4 - Launcher-Live-Ueberblick (LauncherWidgetsPanel, isoliertes UserControl, rechts angedockt,
30s-Refresh; minimaler Eingriff ins von Richard bearbeitete Launcher-Designer):
- Modul-PnL/Winrate-Kacheln (je Modul + Gesamt: Heute/7T/30T, gruen/rot) via TradeAnalytics.
- Supervisor-KI-Kurzfassung (letzter sup_report).
- Warnungen & Fehler (heutige JSONL-Logs, Error/Warning).
- Auffaellige Trades (24h, nach |PnL| sortiert).

Regressionen aus VS-Re-Serialisierung behoben (VS liess hand-erstellte DataGridView-Spalten fallen
-> col* null -> NRE beim Oeffnen):
- DashboardView (dgvTrades): Spalten-Instanziierung + AutoGenerateColumns=false + Columns.AddRange
  + Spalten-Konfig wiederhergestellt.
- JobsView (dgvJobs): dito (nur Button-Spalte hatte ueberlebt).
- Smoke-UI dauerhaft um JobsView/TerminalView/SettingsView erweitert -> faengt diese Regressionsklasse
  kuenftig ab.

Enthaelt ausserdem Richards zwischenzeitliche UI-Arbeit (Launcher-Icons cross_reference/emotion_batman/
file_start_workflow, Designer-Re-Serialisierungen, .ico-Sammlung, Modul-Form-.resx). Persoenliche
Notizdatei bewusst NICHT committet.

Build 0 Fehler, 396 Tests gruen, --smoke-ui alle 9 Views/Forms gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 09:31:59 +02:00
RichardandClaude Opus 4.8 936144c318 UI Slice 2: Settings-Fenster Scaling-Fix + OpenRouter-Key konfigurierbar
Scaling-Bug behoben (war 'teilweise unbenutzbar'):
- General Settings: toolStrip2 war NICHT gedockt (floatete), propertyGrid war Dock=Bottom mit
  fixer Hoehe -> jetzt toolStrip2 Dock=Top, propertyGrid Dock=Fill (Controls-Reihenfolge korrigiert).
- Accounts: toolStripAccounts Dock=Top (war floatend); Grid Left + PropertyGrid Fill bleiben.
- Form: tabControl1 Dock=Fill statt Anchor mit falscher Groesse; leere toolStrip1 entfernt;
  ueberhohe ClientSize (1523) korrigiert. Skaliert jetzt sauber mit der Fenstergroesse.

Fehlende Einstellung ergaenzt:
- Button 'OpenRouter-Key setzen …' (General Settings, via Designer): maskierte Eingabe, schreibt
  in die gitignorierte openrouter.key (genau das liest der OpenRouterClient) - KEIN Secret im
  Klartext in server_settings.xml. Leer = entfernen. Hinweis auf Spend-Limit.

Build 0 Fehler, --smoke-ui gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 20:54:44 +02:00
RichardandClaude Opus 4.8 0725a81dbd UI Slice 3: CopyTrading - Zeilenfaerbung, Filter, Offene-Trades-Tab, Master-Grid-Fix
- Geschlossene Trades: Zeilenfaerbung nach PnL-% (TradeRowColoring, pur+getestet: <0 rot,
  0-10% hellgruen, >10% gruen) via DataBindingComplete. Filter-Panel (Designer): Markt (Text),
  Master-Trader (Combo, dynamisch), Ergebnis (Alle/Gewinner/Verlierer), Von/Bis (optionale
  DateTimePicker mit Checkbox), Zuruecksetzen. Summary zeigt gefiltert/gesamt.
- Neuer Tab 'Offene Trades' (OpenTradesView, designerfaehig): alle offenen Positionen aus dem
  Laufzeit-State mit Entry/Aktuell/Wert/Buchgewinn/-% und Status (offen/Exit laeuft), Zeilenfaerbung
  nach Buchgewinn-%, Summenzeile. In CopyTradingMainForm zwischen Master-Trader und Geschlossene eingehaengt.
- Master-Trader-Grid: AutoSizeColumnsMode=Fill + FillWeights -> Spaltenbreiten teilen sich immer die
  Breite (Fix der 'verbuggten' Breiten); RowHeader war bereits aus.

Tests: +8 (TradeRowColoring-Schwellen). Build 0 Fehler, 396 Tests gruen, --smoke-ui gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 20:49:41 +02:00
RichardandClaude Opus 4.8 25f0d34042 UI Slice 1b: Fenster-Menue auf ALLEN Fenstern (zentrale Shell-Injektion)
ShellUiHost injiziert das gemeinsame 'Fenster'-Menue beim Oeffnen zentral in jedes Fenster
(nur wenn keins eigenes vorhanden ist, z.B. Launcher). Damit erscheint das Menue auf allen
Core- und Modul-Fenstern ohne Achtfach-Designer-Duplikat, und jedes kuenftige Fenster bekommt
es automatisch. Inhaltliche Controls bleiben designerbasiert; das Nav-Menue ist Shell-Chrome.

Tests: +3 (WindowMenu.Populate: Inhalt Launcher/Views/Beenden, aktuelles Fenster fett+angehakt,
offenes angehakt, Klick navigiert). 389 Tests gruen, --smoke-ui gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 18:34:45 +02:00
RichardandClaude Opus 4.8 f54cd7423b UI Slice 1a: Shell-Fundament + Launcher-Buttons statisch + Fenster-Menue + maximiert
- IModuleUiHost (Core) um Navigation erweitert: Views/IsOpen/OpenView/ActivateMain/OpenStateChanged
  + optionales Icon je ModuleView. So kann JEDES Fenster (auch Modul-Fenster, die nur Core kennen)
  das gemeinsame Fenster-Menue bauen.
- WindowMenu (Core): baut das 'Fenster'-Dropdown (Launcher + alle Views + Beenden), haakt offene
  Fenster an, markiert das aktuelle fett; Neuaufbau beim Aufklappen.
- ShellUiHost: SetMainWindow/ActivateMain; oeffnet ALLE Fenster jetzt MAXIMIERT (Vorgabe).
- Launcher: alle Modul-/Core-Buttons STATISCH im Designer (btn_copytrading/-resolutionfarming/
  -supervisor ergaenzt), an View-IDs gebunden; fehlt eine View -> Button deaktiviert. Dynamischer
  Laufzeit-Anhang ENTFERNT -> kein doppelter Accounting-Button mehr; leerer btn_accounting_Click raus.
  Datei/Beenden -> Fenster-Menue (WindowMenu). Launcher startet maximiert (Sizable, MinSize 1280x720).

Build 0 Fehler, --smoke-ui alle 6 Views + Launcher gruen. Fenster-Menue auf den uebrigen Fenstern folgt (1b).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 18:30:30 +02:00
RichardandClaude Opus 4.8 ca0d4ceed0 Accounting A-4 (PDF): neutrale Abrechnung als PDF via PDFsharp/MigraDoc (MIT)
Vervollstaendigt den Export (CSV war A-2) um PDF - laenderneutral, KEINE steuerliche Einordnung.
PDFsharp/MigraDoc-GDI 6.2.4 (echte MIT ohne Umsatzschwelle; GDI-Variante nutzt System-Fonts auf
Windows/WinForms; keine NU1701-Transitiven - bewusst NICHT QuestPDF).

- PdfExporter (Logic): Kopf (Konto/Zeitraum/Waehrung/Datum) + Aggregat-Tabelle + Monatsvergleich +
  Transaktionsliste + Methodik-/Nachweis-Seite (append-only-Quelle, Cash-Basis, 'keine Steuerberatung',
  SHA-256-Daten-Hash fuer Reproduzierbarkeit). Betraege in Anzeige-Waehrung (Faktor uebergeben ->
  Services-unabhaengig). Landscape.
- UI: Button 'PDF-Export' (via Designer) neben CSV; Export via SaveFileDialog in gewaehlter Waehrung.
- Test: PdfExporter erzeugt valide PDF-Bytes (%PDF-Signatur) headless -> MigraDoc-Rendering verifiziert.

Build 0 Fehler, 386 Tests gruen, --smoke-ui alle 6 Views gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 15:10:52 +02:00
RichardandClaude Opus 4.8 42a599a3a3 Accounting A-2: neutrale Periodenabrechnung + BWA-Uebersicht + FX + CSV-Export
Alles laenderneutral, ohne steuerliche Einordnung (A-3 US-Steuerschicht bleibt bewusst offen,
haengt an den CPA-Fragebogen-Antworten). Konzept: docs/konzepte/KONZEPT-Modul-Accounting.md, A-2.

Pure Logik (unit-getestet):
- AccountingEngine.BuildStatement: aggregiert Ledger-Saetze eines Zeitraums (x Account/alle) zu
  Anfangs-/Endsaldo, Ein-/Auszahlungen, Handelsvolumen, Redeems, Rewards, Fees und
  Netto-Handelsergebnis (Cash-Basis, EXKL. Ein-/Auszahlungen); Invariante Endsaldo-Anfang =
  Ergebnis + Einz. - Ausz. BuildMonthlyBreakdown: Monatsvergleich mit verketteten Anfangssalden.
- FxConverter: USDC->USD (dokumentierte 1:1-Annahme) + USD->EUR ueber amtliche Tageskurse
  (acc_fx_rates, Nearest-on-or-before fuer Wochenend-/Feiertage).
- CsvExporter: Ledger + Statement als RFC-4180-CSV, kulturinvariant (Punkt-Dezimal, ISO-Datum).

Infrastruktur:
- acc_fx_rates (FxRate, PK Datum) + EfFxRateRepository (Upsert je Datum). Migration AddFxRates angewendet.
- ILedgerRepository.GetUpTo (alle Saetze <= to fuer die Abrechnung inkl. Anfangssaldo).
- AccountingReportService: baut Abrechnungen + Waehrungs-View (USDC/USD immer, EUR wenn Kurse geladen).

UI (designerfaehig, partial + .Designer.cs): neuer erster Tab 'Uebersicht / BWA' mit KPI-Kacheln
(Netto-Handelsergebnis gruen/rot, Endsaldo, Ein-/Auszahlungen, Fees, Rewards, Volumen, #Trades),
Monatsvergleich-Grid, Zeitraum-Picker (Standard laufender Monat), Konto- und Waehrungswahl, CSV-Export
via SaveFileDialog.

Tests: +6 (Periodenaggregation+Invariante, Monatsverkettung, FX-Umrechnung/Nearest-Kurs, CSV-Quoting).
Build 0 Fehler, 385 Tests gruen, --smoke-ui alle 6 Views gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 15:06:13 +02:00
RichardandClaude Opus 4.8 a3c145c0ed Accounting A-1: Ingest-Fundament (unabhaengiger Ledger, idempotent, read-only)
Neues Modul PolyTrader.Modules.Accounting (IPolyTraderModule, acc_-Praefix, nur Core-Referenz,
KEIN Handel). Konzept: docs/konzepte/KONZEPT-Modul-Accounting.md, Phase A-1.

Buchungsgrundlage ausschliesslich aus unabhaengigen Polymarket-/On-Chain-Abrufen (nie unsere
Trading-DB), append-only, prueffaehig:
- Modelle: LedgerEntry (+ LedgerEventType), IngestRun (mit Balance-Anker), RawSnapshot,
  RawActivity/RawTransfer (normalisierte Eingaben, entkoppeln pure Logik von der API-Feldbenennung).
- AccountingClassifier (Logic/, pur+getestet): Activity->Buchungssatz (Typ/Vorzeichen: BUY=Cash raus
  inkl. Fee, SELL=Cash rein minus Fee, Redeem/Reward +, Split/Merge/Conversion geldneutral),
  stabiler Idempotency-Key; Transfer-Klassifikation trennt intern (System-Contract-Whitelist) von
  externen Deposits/Withdrawals. SumNet fuer den Balance-Anker-Abgleich.
- AccountingDbContext (acc_ledger append-only + Unique-Index Idempotency, acc_ingest_runs, acc_raw;
  Autoincrement-PKs). Migration InitialAccounting generiert UND angewendet. Repos mit idempotentem
  Upsert (true=neu/false=Duplikat).
- AccountingIngestService (BackgroundService): testbarer IngestAccountAsync - Activity + On-Chain-
  Transfers klassifizieren + idempotent buchen, Rohschnappschuss ablegen, Lauf inkl. Balance-Anker-
  Delta protokollieren; Backfill vs. inkrementell (Lookback-Ueberlappung gegen API-Lag).
- Quellen hinter Interfaces (IActivitySource/ITransferSource/IBalanceAnchorSource) mit Null-Stubs:
  Modul laeuft offline und bucht korrekt nichts. Live-Abruf + System-Contract-Whitelist = Zielland.
- UI designerfaehig (partial + .Designer.cs): Tabs Ledger (filterbar) + Abruf/Status (Ingest-Laeufe,
  Balance-Anker, manueller Backfill/Inkrement).
- Program.cs (beide Modul-Listen) + sln + App/Tests-Referenzen.

A-2 (Abrechnung/BWA/FX), A-3 (US-Steuerschicht FIFO/Form-8949), A-4 (CSV/PDF via PDFsharp/MigraDoc)
folgen. Tests: +12 (Klassifikation, intern/extern-Transfer, Ingest-Idempotenz, Balance-Anker,
Inkrement-Fenster). Build 0 Fehler, 379 Tests gruen, --smoke-ui alle 6 Views gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 08:54:12 +02:00
RichardandClaude Opus 4.8 c7668170a4 Supervisor S-3-Rest + RF-Designer-Konvertierung: Counterfactual, Tagesbericht, UI
RF-UI designerfaehig (Richards Vorgabe, letzter code-only-Altbestand):
- ResolutionFarmingMainForm auf partial + .Designer.cs umgestellt (4 Tabs Kandidaten/
  Positionen/Historie/Settings, alle Controls im Designer; Verhalten unveraendert).

S-3 Counterfactual ('Was waere aus abgelehnten BUYs geworden?'):
- CounterfactualJob (alle 6h, API-gedrosselt): nimmt Rejected-BUY-Entscheidungen mit
  abgelaufenem MarketEndDate aus dem Journal, prueft die Marktaufloesung
  (ICounterfactualResolutionSource; live = Adapter um CheckMarketResolutionAsync) und
  speichert IsWinner + hypothetischen PnL/Share (CounterfactualMath, pur) nach
  sup_counterfactuals (unique je DecisionId -> idempotent). Migration generiert+angewendet.
- Agent-Tool query_counterfactuals + UI-Tab 'Counterfactual' (via Designer).

S-3 Threema-Tagesbericht:
- DailyReportService: taeglich zur konfigurierten Stunde (OPT-IN via
  POLYTRADER_SUPERVISOR_DAILY=0-23) laesst der Agent einen 24h-Kurzbericht erstellen
  (KPIs je Modul, Fehler, Reject-Haeufungen), sendet via Threema und legt ihn als
  sup_report ab. Ohne OpenRouter-Key: stiller Skip mit Log.

Tests: +7 (CounterfactualMath, Job aufgeloest/unaufgeloest/idempotent, Tagesbericht
mit/ohne Key). Build 0 Fehler, 367 Tests gruen, --smoke-ui alle 5 Views gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 11:14:45 +02:00
RichardandClaude Opus 4.8 b7b2a141e3 Supervisor S-3/S-4: MCP-Light-Server, Profile, gespeicherte Berichte, Designer-UI
S-4 MCP-Light (Daten-Tuer fuer externe KI-Clients, KEIN Modell-Zugang - Modelle laufen
weiter ueber OpenRouter):
- McpJsonRpc (pur): JSON-RPC 2.0 fuer initialize/ping/tools/list/tools/call ueber die
  read-only Tool-Registry; Notifications/Fehlerfaelle spezifikationskonform.
- McpLightServer (HostedService): lokaler Streamable-HTTP-Endpoint. OPT-IN via
  POLYTRADER_MCP_PORT, bindet NUR 127.0.0.1. Claude Code:
  claude mcp add --transport http polytrader http://127.0.0.1:PORT/mcp
- End-to-End-Test ueber echtes HTTP (initialize, tools/call, Notification=202, GET=405).

S-3 Profile + Berichte:
- SupervisorProfiles: Allgemein/Technik/CopyTrading/ResolutionFarming als System-Prompt-
  Zusatz + Tool-Subset ueber EINER Agent-Infrastruktur (Technik z.B. ohne Strategie-Tools).
  Agent filtert Tools je Profil.
- sup_reports (SupervisorDbContext, Migration generiert UND angewendet): jede Analyse wird
  mit Profil/Modell/Frage/Antwort/Tool-Aufrufen/Token gespeichert -> Supervisor auditierbar.

UI (Richards Vorgabe: designerfaehig):
- SupervisorMainForm auf partial + .Designer.cs umgestellt - alle Controls im Designer
  (3 Tabs: Analyse mit Profil-Combo+Modellfeld, Dossiers, Berichte mit Split/Grid/Detail).

Tests: +16 (MCP-JSON-RPC 6, MCP-HTTP-E2E 1, Profile 2, bestehende erweitert). Build 0 Fehler,
360 Tests gruen, --smoke-ui alle 5 Views gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 11:00:28 +02:00
RichardandClaude Opus 4.8 5d732277b2 Supervisor S-2: OpenRouter-Agent, read-only Tool-Registry, Analyse-Chat
Der KI-Analyse-Agent (docs/konzepte/KONZEPT-Modul-Supervisor.md, Phase S-2):
- SupervisorToolRegistry (transport-agnostisch, spaeter auch MCP-Light): 7 read-only-Tools -
  query_decisions (inkl. Rejects+ReasonCodes), query_order_events, query_trades, get_dossier
  (Markdown-Kette), read_logs (JSONL je Tag, CID-Filter), get_kpis (TradeAnalytics),
  get_architecture_context. Ausfuehrung fehlertolerant (Exception -> Fehlertext, wirft nie).
  KEIN Tool kann handeln/schreiben.
- OpenRouterClient (IChatCompletionClient): OpenAI-kompatibles Chat-Completions-Schema inkl.
  Function-Calling; Request-Bau + Response-Parsing pur/testbar. API-Key GETRENNT vom Trading:
  env POLYTRADER_OPENROUTER_KEY oder gitignorierte openrouter.key (in .gitignore aufgenommen).
- SupervisorAgent: Function-Calling-Loop (max 8 Iterationen), System-Prompt = Arbeitsanweisung +
  eingebettetes Architektur-Kontext-Dokument (Context/ArchitectureContext.md, EmbeddedResource,
  mit dem Code versioniert - beschreibt Entscheidungswege, ReasonCodes, Leiter-Mechanik, Eigenheiten).
  Tool-Aufrufe werden gesammelt und in der UI transparent angezeigt.
- SupervisorMainForm: neuer Tab 'Analyse' (Chat, Modellwahl default openrouter/auto, Tool-Aufrufe
  live im Verlauf, Token-Zaehler) neben dem Dossiers-Tab.
- Sicherheitskonzept: OpenRouter als bewusst freigegebener Egress dokumentiert (nur Tool-Ergebnisse,
  nie Secrets; Spend-Limit je Key empfohlen).

Tests: +7 (Registry-Ausfuehrung/Fehler, Agent-Loop mit Tool-Rueckfluss, Iterationsgrenze,
Request-Body/Response-Parsing, eingebetteter Kontext). Build 0 Fehler, 351 Tests gruen,
--smoke-ui alle 5 Views gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 18:06:28 +02:00
RichardandClaude Opus 4.8 c75a958e36 Supervisor S-1: Dossier-Generator + Modul-Skelett mit Dossier-Browser + Journal-Nachverdrahtung
Neues Modul PolyTrader.Modules.Supervisor (IPolyTraderModule, Name=Supervisor, DbPrefix=sup_,
nur Core-Referenz, strikt read-only):
- DossierBuilder (Core/Analytics, pur+getestet): TradeDossier aus Entscheidungen + Order-Events +
  Trades + Log-Zeilen, chronologisch, mit Markdown-Rendering (Tabellen, Pipe-Escaping).
- DossierService (Modul): beschafft Journal/Events/Trade-Log per SignalId + JSONL-Zeilen per CID
  (nur Tagesdateien im Ereignis-Zeitfenster +-1 Tag); RecentSignals-Uebersicht (Journal gruppiert).
- SupervisorMainForm: Dossier-Browser - links juengste Signale, rechts Markdown-Dossier;
  SignalId-Suche; Analyse-Chat (OpenRouter) folgt in S-2. In Launcher/Smoke registriert.

Journal-Nachverdrahtung (S-0-Vervollstaendigung):
- TraderMonitor: Profit-Target erzeugt eigene SignalId -> Leiter + Journal (ProfitTargetTriggered);
  Stale-Cleanup-Cancels als OrderEvents (StaleCleanupCancel).
- StartupOrderReconciliation: K2-Cancels als OrderEvents (StartupReconcileCancel).
- RF: Demo-Einstiege (DemoFilled, eigene SignalId) + Resolution-Closes (SystemResolutionClose)
  im Journal - damit sind ALLE Module im Entscheidungsjournal vertreten.

Tests: +3 DossierBuilder; 4 Service-Builder auf neue Ctors. Build 0 Fehler, 344 Tests gruen,
--smoke-ui: [OK] supervisor.main (alle 5 Views gruen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 10:09:02 +02:00
RichardandClaude Opus 4.8 ca00977ea3 Supervisor S-0c: Log Viewer im Terminal (JSONL menschenlesbar, CID-Forensik)
Terminal-Fenster jetzt mit TabControl (via Designer): Tab 'Live' = bisherige Anzeige,
Tab 'Log Viewer' = JSONL-Tagesdateien menschenlesbar aufbereitet:
- Filter: Datum (DateTimePicker), Level, CorrelationId (SignalId), Suchtext.
- Doppelklick auf eine CID laedt die komplette Signal-Kette ('zeig mir alles zu diesem Signal').
- LogJson.ParseLine (pur, Gegenstueck zu Format): tolerant gegen kaputte Zeilen (null statt Crash);
  Viewer ueberspringt sie. UI-Schutz bei sehr grossen Tagen (20k-Limit).

Tests: +5 (Parse-Roundtrip, kaputte Zeilen). Build 0 Fehler, 341 Tests gruen, --smoke-ui komplett gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 18:52:15 +02:00
RichardandClaude Opus 4.8 bf3e012f8b Supervisor S-0a/b: Entscheidungsjournal, Order-Events, SignalId, JSONL-Logs
Datenfundament fuer die KI-Analyse (docs/konzepte/KONZEPT-Modul-Supervisor.md, Phase S-0).
Sofortnutzen auch ohne KI: abfragbare Rejects, rekonstruierbare Order-Ketten.

- core_decision_journal (DecisionRecord): JEDE Handelsentscheidung strukturiert -
  Decision (Executed/Rejected/Skipped/Failed) + ReasonCode-Enum (als String, erweiterbar)
  + Kontext-JSON (kulturinvariant) + MarketSlug/EndDate (counterfactual-ready).
- core_order_events (OrderEventRecord): Order-Lifecycle als Daten (Placed/PlaceFailed/
  LadderStart/LadderStep/FloorReplaced/DustAbort ...) inkl. CLOB-Response.
- SignalId (GUID) auf CopySignal, durchgereicht bis ClosedTrade + Core-TradeRecord
  (Dual-Write) und in die Leiter (ExitLadderState.SignalId) -> Dossier-Korrelation.
- CopyTradingEngine: ~20 Entscheidungs-Sites journalisieren zusaetzlich zum Freitext-Log
  (Mode/SellOnly/H3/MaxBuyPrice/PerMaster/TimeLimit/Budget/Balance/Minimum/SpamBlock/
  Leiter/Ownership/NotFound/Teilverkauf/Inkonsistenz/Grace/Demo-Fill/-Close/Live-BUY).
- SellLadderService: Order-Events fuer Start/Step/Floor-Replace/Dust; IOrderEventLog injiziert.
- TerminalLogger: JSONL-Sink (eine Datei/Tag, LogJson pur) + CorrelationId-Support. Dual-Sink.
- Journal-Writes fehlertolerant (brechen den Geld-Pfad nie).
- Migrationen offline generiert UND angewendet (rein additiv): Core (Widen F1 + Journal),
  CopyTrading (SignalId), RF (Initial) - DB war bis AddMarketTakerFeeBps migriert, verifiziert.
- Launcher-Designer: Account-Spalten-Instanziierung wiederhergestellt (war bei Designer-
  Reserialisierung verloren gegangen -> NullReference im Smoke).

Tests: +5 (LogJson, Journal-Roundtrips, SignalId) + Journal-Assertions in Engine-Tests.
Build 0 Fehler, 336 Tests gruen, --smoke-ui komplett gruen (alle Views inkl. RF gegen echte Tabellen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 18:48:25 +02:00
RichardandClaude Opus 4.8 eac47369f0 Docs: Supervisor-Konzept erweitert (Predictalytics-Quelle, Profil-Team, JSONL+Log-Viewer)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 10:36:09 +02:00
RichardandClaude Opus 4.8 8b79c35851 Docs: Konzept Supervisor-Modul (KI-Analyse, Entscheidungsjournal, Dossiers)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 10:09:50 +02:00
RichardandClaude Opus 4.8 b6dff7e210 UI: Dashboard-Ueberarbeitung (Scope-Filter, KPIs, ScottPlot-Charts, Tradehistorie)
Das Dashboard ist keine stumpfe Trade-Liste mehr, sondern ein Auswertungs-Fenster:
- ToolStrip (via Designer): Scope-Filter Konto/Modul/Live-Demo/Zeitraum + Aktualisieren.
- TabControl mit 2 Tabs:
  - Dashboard: KPI-Kacheln (Netto-PnL/Winrate/Trades/O-PnL/Profit-Faktor) + 3 Charts
    (Equity-Kurve, PnL je Modul, PnL je Tag) fuer den gewaehlten Scope.
  - Tradehistorie: gefilterte Trade-Liste (Spalten via Designer) + Suche + Gewinner/Verlierer.
- Charts via ScottPlot CORE-Paket (nur SkiaSharp, .NET-nativ) -> als Bitmap in PictureBoxen
  gerendert; KEINE OpenTK/.NET-Framework-Transitiven (bewusst nicht ScottPlot.WinForms).
- Auswertungslogik pur in TradeAnalytics (getestet). In-Memory-Filter auf gecachtem Recent-Set.
- Smoke-UI konstruiert die DashboardView jetzt direkt -> verifiziert das Chart-Rendering headless.

Build 0 Fehler, 331 Tests gruen, --smoke-ui: [OK] core.dashboard konstruiert (inkl. Charts).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 19:54:49 +02:00
RichardandClaude Opus 4.8 7d63791e38 UI: Launcher-Account-Uebersicht + pure TradeAnalytics-Fundament
- TradeAnalytics (Core, pur/testbar): KPIs (Netto-PnL/Winrate/Ø/Profit-Faktor), Equity-Kurve,
  PnL je Modul/Account/Tag, Window-Summary. Speist Dashboard + Launcher. 7 Tests.
- Launcher dgv_accountlist: Spalten via Designer (Account, Module, Polymarket-Button, Wallet-USDC,
  3T-PnL, 3T-Winrate, Overall P/L). Daten je Account aus dem Core-Trade-Log via TradeAnalytics;
  Auto-Refresh alle 30 s; Polymarket-Button oeffnet das Wallet-Profil. DB-Abfragen fehlertolerant.

Build 0 Fehler, 331 Tests gruen, --smoke-ui ok (Launcher laedt Uebersicht).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 09:59:10 +02:00
RichardandClaude Opus 4.8 0aedddabe8 UI: Terminal-Kopierfunktion (Kontextmenue) + Jobs-Toolstrip (via Designer)
- TerminalView: ContextMenuStrip (Kopieren/Alles auswaehlen/Alles kopieren/Terminal leeren)
  am rtbTerminal - macht das Kopieren entdeckbar (Ctrl+C funktioniert zusaetzlich nativ).
- JobsView: ToolStrip 'toolStripJobs' (docked Top) mit Starter-Button 'Aktualisieren'
  (dgvJobs.Refresh) - weitere Job-Steuerelemente folgen nach und nach.
Beide via Designer (.Designer.cs), Logik im Code-Behind. Build 0 Fehler, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 09:39:35 +02:00
RichardandClaude Opus 4.8 4df07bd3d2 UI: Master-Key-Button (Settings, via Designer) + UI-Designer-WIP + Steuer-PDF
- Settings: neuer Toolbar-Button 'Master-Key erzeugen' (Tab General Settings, via Designer).
  Erzeugt zufaelligen 32-Byte-AES-Key -> master.key (gitignored), nur aktiv wenn KEIN Key
  existiert (Env-Var oder Datei), Lockout-Schutz + Backup-Warnung, danach deaktiviert.
- Einbezogen: laufende Designer-Umstrukturierung (SettingsView/LauncherForm: Button-Bilder
  aus Properties.Resources statt eingebettet; dgv_accountlist im Launcher; DashboardView.resx).
- docs/steuer: US-CPA-Fragebogen als PDF.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 09:27:34 +02:00
RichardandClaude Opus 4.8 36c89a6acf Security F5/F6 + Konzept-Status: DB-TLS-Startwarnung, Log-Redaction geprueft
- F5: Startwarnung, wenn der DB-Connection-String kein SslMode erzwingt (String selbst wird
  nie geloggt). Eure Connection enthaelt bereits SslMode -> Warnung bleibt aus.
- F6: geprueft - keine Secret-Werte in Logs (nur Vorhandensein-Flags/Fehlermeldungen).
- Sicherheitskonzept: Status F1-F7 dokumentiert.

Build 0 Fehler, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 08:54:50 +02:00
RichardandClaude Opus 4.8 f3ed63cf9d Security F1: Wallet-Keys/API-Secrets at-rest verschluesselt (AES-256-GCM, portabler Master-Key)
Behebt den kritischsten Befund (Klartext-Private-Keys in remote-gehosteter MySQL):
- SecretProtection (Core/Security): AES-256-GCM, authenticated. Master-Key AUSSERHALB der DB
  (env POLYTRADER_MASTER_KEY, sonst gitignorierte master.key). Format enc:v1:base64(nonce|tag|ct).
  Alt-Klartext (ohne Praefix) wird gelesen und beim Speichern verschluesselt (selbstheilend).
  Ohne Master-Key: Passthrough + deutliche Startwarnung (kein stiller Sicherheitsverlust).
- EncryptedStringConverter (EF ValueConverter) auf core_accounts.PrivateKey/ApiSecret/ApiPassphrase;
  Spalten 256->512 verbreitert (Migration EncryptAccountSecretsWidenColumns, offline generiert).
- Program.cs: Master-Key vor der Hydration laden; nach Start einmalige/idempotente Re-Encryption
  vorhandener Klartext-Credentials. Auch in --smoke-ui verdrahtet.
- CoreDbContextFactory nutzt jetzt fixe Server-Version (offline-Migrationsgenerierung, kein DB-Zugriff).

13 neue Krypto-Tests (Round-Trip, Nonce-Frische, Manipulations-/Falscher-Key-Erkennung, Passthrough,
Key-Formate). Build 0 Fehler, 324 Tests gruen, --smoke-ui ok (Warnung ohne Key wie erwartet).

AKTIVIERUNG (im Zielland): POLYTRADER_MASTER_KEY setzen (zufaelliger 32-Byte-Base64-Key, SEPARAT sichern!)
+ Migration anwenden (dotnet ef database update --context CoreDbContext). Danach Alchemy-/Mullvad-Secrets
aus F3 rotieren. WICHTIG: Master-Key-Verlust = Kein Zugriff auf die Keys mehr.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 08:35:59 +02:00
RichardandClaude Opus 4.8 32fda4e70f Security F2: toten Redeem-Anti-Pattern-Code entfernt (Private-Key als CLI-Argument)
Der auskommentierte redeem_markets.py-Aufruf uebergab Private-Key + Secrets als
Prozess-Argumente (in der Prozessliste sichtbar). War deaktiviert, aber latentes Risiko
(reaktivierbar/falsches Muster) -> entfernt. Sicherheitshinweis fuer kuenftiges
Auto-Redeem hinterlegt (Secrets nie via argv; Redeem in .NET/Nethereum).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 16:49:38 +02:00
RichardandClaude Opus 4.8 1a3359e874 Security F3+F4: verwundbares Newtonsoft ersetzt + hardcodierte Secrets entfernt
F4: Newtonsoft.Json in der Threema-Lib von 11.0.2 (Advisory NU1903, high) auf 13.0.4
    gehoben (= App-Version). Build ohne NU1903, 311 Tests gruen.
F3: hardcodierte Secrets aus ServerSettings-Defaults entfernt (Alchemy-API-Key in
    PolygonRpcUrl, Mullvad-Account-ID) -> leere Defaults; echte Werte kommen aus
    server_settings.xml (gitignored). WICHTIG (nicht im Code moeglich): beide Secrets
    ROTIEREN, da sie in der Git-History liegen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 16:48:29 +02:00
RichardandClaude Opus 4.8 faf66102f9 Docs: Software-Sicherheitskonzept (Bedrohungsmodell, Befunde F1-F7, Audit-Checkliste)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 16:45:18 +02:00
RichardandClaude Opus 4.8 c5f0b1d188 Docs: Konzepte/Plaene in docs/ mit Typ-Unterordnern buendeln
Root aufgeraeumt: alle Konzept-/Plan-/Fach-Dokumente nach docs/ verschoben,
organisiert nach Typ (wie fuer ein separates Docs-Repo vorgeschlagen, aber bewusst
in diesem Repo, damit Plan->umsetzende-Commits nachvollziehbar bleiben):
- docs/konzepte/       (KONZEPT-*)
- docs/umsetzungsplaene/ (UMSETZUNGSPLAN-*)
- docs/ideen/          (fruehe Ideen, Platzhalter)
- docs/pruefplaene/    (PRUEFPLAN-*)
- docs/steuer/         (Steuer-/Buchhaltungs-Doks, z.B. US-CPA-Fragebogen)
- docs/README.md       (Index/Konventionen)

Getrackte Plaene als Rename verschoben (History erhalten); zuvor untracked Konzept-/
Plan-Dateien jetzt versioniert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 10:15:08 +02:00
RichardandClaude Opus 4.8 1c3a364df2 RF-Slice 5: Demo-Execution + Resolution-Monitor (Phase RF-2)
Schliesst die Demo-Handelsschleife des ResolutionFarming:
- FarmingExecutionPlanner (pur): waehlt aus akzeptierten Kandidaten die zu oeffnenden
  Positionen + Groesse, priorisiert nach Score, unter Markt-/Cluster-/Gesamt-Limits,
  Kill-Switch und Tages-Drossel; dedupliziert Token, schreibt Exposure im Lauf fort.
- FarmingResolution (pur): baut aus Position + Ergebnis den RfClosedTrade (PnL/Fees/Redeem-Status).
- FarmingExecutionService: Demo-Einstieg (Maker-Fill 0 Fee via FarmingFillModel) -> rf_positions.
  Live-Execution bewusst geloggt/uebersprungen (Zielland). Demo-Balance NICHT mutiert
  (kein Shared-Account-Konflikt; PnL fliesst ueber rf_closed_trades).
- FarmingResolutionMonitorService: schliesst aufgeloeste Positionen, bucht GlobalPnl,
  Dual-Write ins Core-Trade-Log (Dashboard). Auflösungsstatus via IMarketResolutionSource.
- NullMarketResolutionSource als Default (nichts loest auf), bis Live-Data-API verdrahtet ist.

15 neue Tests (Planner 8, Resolution 3, Execution-Service 2, Monitor 2). Build 0 Fehler,
311 Tests gruen, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 11:40:30 +02:00
RichardandClaude Opus 4.8 80e6ad9b2d RF-Slice 4: ResolutionFarming-UI (Tabs Kandidaten/Positionen/Historie/Settings)
Ein Modul-Fenster mit TabControl, code-only konstruiert (kein Designer/.resx):
- Kandidaten: DataGridView der letzten Scans je Konto (akzeptiert+abgelehnt inkl. Grund).
- Positionen: offene rf_positions.
- Historie/Statistik: abgeschlossene Trades + Summary (Winrate gesamt/je 5-¢-Preisband,
  Netto-PnL, Fees) fuer die Kalibrierung.
- Settings: PropertyGrid auf RfSettings je Konto + Speichern (Muster AccountSettingsView).
RegisterUi verdrahtet die View (Launcher-Button 'ResolutionFarming').

DB-Zugriffe defensiv (Guarded try/catch) -> UI bleibt bedienbar auch vor Anwenden der
rf_-Migration (zeigt dann nur Statushinweis statt zu crashen).

Build 0 Fehler, 296 Tests gruen, --smoke-ui konstruiert die RF-View ([OK] resolutionfarming.main).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 22:59:41 +02:00
RichardandClaude Opus 4.8 ad6c676e60 RF-Slice 3: Read-only-Scanner (Bewertungs-Pipeline + Persistenz)
Phase RF-1 (read-only): Scanner holt bald aufloesende Favoriten von einer
IFarmingMarketSource, bewertet sie und schreibt JEDEN Kandidaten (akzeptiert wie
abgelehnt inkl. Grund) nach rf_candidates. Platziert keine Orders.

- MarketScannerService.Evaluate (pur/statisch, voll getestet): Filterkette mit
  Reject-Grund = erster Fehlschlag (Preisband -> Kategorie -> Blacklist ->
  Aufloesungsfenster -> Netto-Edge nach Fees). Cluster-Key + Score immer berechnet.
- ScanAccountAsync: Beschaffung -> Bewertung -> Persistenz. BackgroundService-Loop
  (12min) ueber Accounts mit Settings; fehlertolerant.
- IFarmingMarketSource + ScannedMarket-DTO trennen die (live-/API-gebundene)
  Beschaffung von der Bewertung -> Pipeline ohne echte Gamma/CLOB-API testbar.
- NullFarmingMarketSource als Default: Modul laeuft ohne Live-Anbindung (die im
  Zielland registriert wird) und produziert dann korrekt keine Kandidaten.

Hinweis: Zur Laufzeit fragt der Scanner rf_settings ab; bis die Migration angewendet
ist, faengt der try/catch den fehlenden-Tabelle-Fehler ab (nur Log). Migration bewusst
separat anzuwenden.

7 neue Tests (Evaluate-Faelle + Orchestrierung). Build 0 Fehler, 296 Tests gruen, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 22:11:11 +02:00
RichardandClaude Opus 4.8 1b6e194b50 RF-Slice 2: ResolutionFarming-Persistenz (EF/MySQL) + Repos + Migration
- Entities RfCandidate/RfPosition/RfClosedTrade (+ RfSettings aus Slice 1).
- ResolutionFarmingDbContext: Tabellen rf_settings/rf_candidates/rf_positions/
  rf_closed_trades. Autoincrement-PKs (Identity) fuer Candidate/ClosedTrade von
  Anfang an (Lehre aus dem CopyTrading-TradeId-Problem), zusammengesetzter PK
  (AccountId,TokenId) fuer Positions, Indizes + Decimal-Precision.
- 4 Repos (Settings/Candidate/Position/ClosedTrade) mit serverseitigen Aggregaten
  (RealizedPnlSince fuer Kill-Switch, CountOpenedSince fuer Tages-Drossel).
- Modul registriert DbContextFactory + Repos.
- Design-Time-Factory nutzt die fest gepinnte Server-Version -> Migration wurde
  OHNE DB-Verbindung generiert (kein Zugriff auf die produktive DB). Anwenden per
  'dotnet ef database update' bewusst im Zielland/lokal durch den Nutzer.

6 neue EF-InMemory-Repo-Tests. Build 0 Fehler, 289 Tests gruen, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 22:06:59 +02:00
RichardandClaude Opus 4.8 c9eb11afe4 RF-Slice 1: ResolutionFarming-Modul-Skelett + geldkritische pure Logik + Tests
Neues Strategiemodul PolyTrader.Modules.ResolutionFarming (IPolyTraderModule,
Name=ResolutionFarming, DbPrefix=rf_), in Solution/App/Tests + beide Modul-Listen
in Program.cs eingebunden. Skelett laedt (RegisterServices/UI noch no-op).

Geldkritische Entscheidungslogik pur und vollstaendig unit-getestet:
- FarmingRiskEngine: Netto-Edge nach Fees (NetEdge/NetEdgePct/HasEdge), Positionsgroesse
  unter Markt-/Cluster-/Gesamt-Exposure-Limits (AllowedPositionUsd), Kill-Switch, Tages-Drossel.
- FarmingScanner: Preisband, Kategorie-Whitelist, Blacklist, Cluster-Key (korrelierte
  Favoriten teilen einen Cluster), Kandidaten-Score.
- FarmingFillModel: Shares fuer Budget (2-Dezimal-Floor), Resolve-PnL (Auszahlung - Kosten -
  Entry-Fee, Maker/Taker), Einstiegskosten inkl. Fee. Nutzt Core.FeeModel.
- RfSettings (rf_settings) mit konservativen Defaults + PropertyGrid-Attributen.

39 neue Tests. Build 0 Fehler, 283 Tests gruen, --smoke-ui ok.
Persistenz (DbContext/Migration/Repos), Scanner-/Monitor-Jobs, Execution und UI folgen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 21:43:34 +02:00
RichardandClaude Opus 4.8 2f5270a2f3 RF-Slice 0: FeeModel nach Core (geteilte Markt-Infrastruktur)
Vorbereitung fuer das ResolutionFarming-Modul: FeeModel von
PolyTrader.Modules.CopyTrading.Logic nach PolyTrader.Core.Trading verschoben, damit
mehrere Strategiemodule dieselbe Fee-Logik nutzen koennen (Module duerfen nicht
voneinander abhaengen -> geteiltes gehoert in den Core). CopyTrading-Referenzen +
FeeModelTests auf den Core-Namespace umgestellt. Rein mechanisch, verhaltensneutral.

Build 0 Fehler, 244 Tests gruen, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 21:35:11 +02:00
RichardandClaude Opus 4.8 c091e79869 Docs: Testabdeckung + K3-Korrektur im Plan vermerkt
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 19:42:00 +02:00
RichardandClaude Opus 4.8 2377dc7adb K1a-Testabdeckung: Cleanup schont aktive Leiter (Floor-Deadlock)
Verifiziert den kritischen K1a-Fix mit Integrationstests statt nur per Review
(nach dem K3-Fehlplatzierungs-Fund):
- TraderMonitorService._clob -> IClobClient (verhaltensneutral); CleanupStaleOpenOrdersAsync
  internal. FakeCopyTradeLogRepository ergaenzt.
- 2 Tests: Stale Order mit aktiver Leiter wird NICHT gecancelt; ohne Leiter WIRD sie
  storniert (Kontrast, beweist Nicht-Vacuositaet).

Build 0 Fehler, 244 Tests gruen, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 19:41:09 +02:00
RichardandClaude Opus 4.8 f4045f08e1 Engine-Testabdeckung (Guards) + K3-Korrektur am echten Bug-Ort
Testabdeckung fuer den geldkritischen Engine-Pfad (bisher 0 Tests), da die
Fable-Guards zwischen Services entstehen und Unit-Tests sie nicht fangen:
- Engine._clob -> IClobClient (verhaltensneutral, DI registriert IClobClient bereits);
  ProcessAccountOrderAsync internal. FakeMarketRepository/FakeAccountRepository ergaenzt.
- 7 Integrationstests (CopyTradingEngineTests) ueber gemockten CLOB: H3 BUY-Skip bei
  ExitPending, Doppel-SELL-Guard, K3 System-Close (TraderId==0) schliesst Fremd-Position,
  Fremd-Trader-SELL bleibt abgewiesen, H2 Cleanup schont Leiter (+ Kontrast ohne Leiter).

DABEI ECHTEN BUG GEFANGEN: Der K3-Fix aus Slice 3 sass an der falschen Stelle
(IsAuthorizedSell nach dem Position-Remove, Zeile ~643) – der eigentliche Ownership-Check
ist der fruehe inPortfolio-Lookup (Zeile 437, p.SourceTraderId == signal.TraderId), der
System-Signale schon vorher mit early return abwies. Fix jetzt am richtigen Ort; der
downstream-Check bleibt als Defense-in-depth. Ohne den Engine-Test waere das unentdeckt geblieben.

Build 0 Fehler, 242 Tests gruen, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 19:38:11 +02:00
RichardandClaude Opus 4.8 782c08a860 Slice 6 (Fable-Fixes): Totcode/Demo-Balance/Settings-Validierung + Plan-Abschluss
- Totcode: services/SnapshotService.cs entfernt (nirgends registriert).
- Demo-Balance/PnL-Reconciliation: Demo-BUY zieht jetzt die Entry-Fee ab, Demo-Close
  schreibt netto (exitUsd - Exit-Fee) gut -> Summe(Balance-Aenderungen) = Summe(PnL)
  statt um die Fees zu driften (Demo als Validierung konsistent).
- Settings-Validierung: SellLogic.IsLadderConfigInverted (Max-Preisabstand >= SELL-Floor
  -> Leiter startet am Floor) + Warnung beim Settings-Laden (StartupHydration).

Bewusst als Follow-up dokumentiert (Live-Verifikation/Risiko): M3-Autoincrement-Migration,
PersistenceService-Dedup-Zeitfenster, Perf (UpsertLive-Dirty-Check, Leiter-Parallelitaet).

Tests: +3 (IsLadderConfigInverted). Build 0 Fehler, 236 gruen, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 18:45:52 +02:00
RichardandClaude Opus 4.8 84b2b276d9 Slice 5 (Fable-Fixes): H3 – BUY-Skip waehrend ExitPending
Entscheidung Richard (Variante A): Re-buyt der Master, waehrend unsere SELL-Leiter
die Position abverkauft, wird der BUY uebersprungen statt zugekauft. Sonst stockte
der BUY die Position auf, die die Leiter danach inkl. neuer Shares zum alten Floor
verkauft (oekonomisch widerspruechlich). Die Leiter fuehrt den Exit sauber zu Ende.

Guard am Anfang des Engine-BUY-Pfads (spiegelt den bestehenden SELL-ExitPending-Guard).
Build 0 Fehler, 233 Tests gruen, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 18:41:26 +02:00
RichardandClaude Opus 4.8 bdcd3641e4 Slice 4 (Fable-Fixes): H4/M1/M2/M3-min/M4/M6 + Doku
H4 – Rundungs-Dust-Reject-Schleife:
- SellLogic.RoundToTick (0.001, AwayFromZero, wie CalculateExactOrderAmounts). Die
  Leiter platziert Preise gerundet -> usdc = size × Preis geht exakt auf (kein Dust).
- ProcessLadderAsync bricht ab, wenn pos.Size < MinShares (Dust-Rest gehalten,
  ExitPending=false), statt endlos Sub-Minimum-Orders zu schicken.

M1 – GlobalPnl-Doppelzaehlung: in beiden Live-Close-Bloecken jetzt NUR innerhalb des
_processedClosures-Dedup-Guards gebucht (API-Lag zaehlte sonst doppelt).
M2 – TokenId in beiden Live-Close-Records gesetzt (sonst greift die Dedup nach Neustart nicht).
M3 (Minimum) – TradeId-Init: serverseitiges GetMaxTradeId() statt Full-Table-Find(_=>true).Max();
  Fehlschlag wird laut geloggt statt still geschluckt. (Autoincrement-Migration bewusst als
  Follow-up aufgeschoben – Schema-Aenderung an der Trade-Persistenz erst im Zielland live verifizieren.)
M4 – MongoExportParser ProfitTarget-Default 50 -> 9999 (Take-Profit bleibt dormant).
M6 – Fee-Satz (real oder Kategorie-Fallback, FeeModel.ResolveBps) in alle signierten Orders:
  Engine-BUY, SELL-Leiter (Start/Step/Floor), PreRedeem (WSS + REST). API-gated, im Zielland verifizieren.
Doku – stale [Description]: ProfitTarget/SellFloorPct als IMPLEMENTIERT markiert.

Tests: +10 (RoundToTick, Dust-Abbruch, ResolveBps). Build 0 Fehler, 233 gruen, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 14:03:00 +02:00
RichardandClaude Opus 4.8 8252219163 Slice 3 (Fable-Fixes): K3 Demo-Resolution + M5 Demo-Score/Auto-Pause
K3 – Demo-Auto-Close bei Marktauflösung funktioniert wieder:
- System-SELLs (TraderId==0) sind vom Ownership-Check ausgenommen. Regel in reine
  CopyTradingRisk.IsAuthorizedSell(signalTraderId, positionSourceTraderId) extrahiert
  (System ODER Besitzer) und in der Engine genutzt. Vorher lehnte der Check jedes
  System-Close ab (Copy-Positionen haben SourceTraderId>0) -> Demo-Positionen
  schlossen bei Resolution nie, 30s-Loop feuerte endlos.
- Resolved-Cache (_resolvedDemoMarkets) in PollDemoExpirationsAsync: aufgeloeste
  Maerkte werden nicht erneut angefragt (kein Log-Spam / keine unnoetige API-Last).

M5 – Auto-Pause in der Demo-Phase nicht mehr wirkungslos:
- Anzeige-Spalten (CopyPnl30d etc.) zeigen Live-Kennzahlen, sobald vorhanden, sonst
  Demo-Kennzahlen -> Demo-Validierung ist sichtbar statt leer.
- Harte Auto-Pause wirkt bewusst NUR auf Live-Ergebnissen.
- Kadenz: stuendlicher Light-Check (Auto-Pause) statt nur alle 12h; schwere
  History-Analyse bleibt 12h (schliessen sich pro Tick aus, kein Doppellauf).

Tests: 5 neue (IsAuthorizedSell). Build 0 Fehler, 223 Tests gruen, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 13:33:24 +02:00
RichardandClaude Opus 4.8 a3d3d50681 Docs: Fortschritt Slices 0-2 im Plan vermerkt
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 13:20:26 +02:00
RichardandClaude Opus 4.8 98109b78f6 Slice 2 (Fable-Fixes): K2 – Neustart-Reconciliation
Ruhende GTC-Leiter-/MakerEntry-Orders ueberleben Neustarts auf dem CLOB, der
Verwaltungszustand (ExitLadders/ExitPending/PendingOrderTimestamps) ist transient.
Ohne Bereinigung liefe die Engine gegen Waisen-Orders (Doppel-Leiter, Kaskaden).

- StartupOrderReconciliationService (IHostedService): storniert beim Start je
  Live-Account alle offenen CLOB-Orders; danach entscheidet die Engine sauber neu.
  Registriert als ERSTER Modul-HostedService (nach Hydration, vor Monitor/Engine),
  pro Account fehlertolerant.
- GetOpenOrdersAsync: assetId jetzt optional (default "") -> ohne Filter ALLE
  offenen Orders des Accounts. Signaturneutral (HMAC geht ueber Pfad ohne Query),
  rueckwaertskompatibel fuer die bestehenden per-Asset-Aufrufer. IClobClient +
  FakeClobClient nachgezogen.

Hinweis: "/data/orders ohne asset_id = alle Orders" ist API-gated und im Zielland
live zu verifizieren (wie M6).

Tests: 3 neue (cancelt alle Orders je Live-Account, ueberspringt Demo/credential-los,
no-op ohne offene Orders). Build 0 Fehler, 218 Tests gruen, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 13:20:03 +02:00
RichardandClaude Opus 4.8 0200a726e7 Slice 1 (Fable-Fixes): Leiter-Ownership – K1/H2/H1
Wer darf die ruhende Leiter-Order anfassen? Nur die Leiter selbst.

- H1 (Race): StartLadderAsync macht ZUERST einen atomaren Claim
  (ExitLadders.TryAdd). Master-SELL (Engine) und Profit-Target (Sync) sind
  damit idempotent – kein Doppel-GTC / keine Fehlerkaskade. Verliert ein
  Aufrufer den Claim, wird die (evtl. von der Engine entfernte) Position als
  ExitPending zurueckgestellt – kein Waise. Order-Fehler gibt den Claim zurueck.
- K1a (Floor-Deadlock): CleanupStaleOpenOrdersAsync ueberspringt Keys mit
  aktiver Leiter (ExitLadders.ContainsKey) – cancelt die Floor-Order nicht mehr.
- K1b (Floor-Robustheit): ProcessLadderAsync prueft am Floor via GetOpenOrders,
  ob die SELL-Order noch ruht; falls nicht (Cleanup/extern/Teil-Fill), neu
  platzieren statt bis zum Neustart unverkaeuflich zu haengen.
- H2 (Engine-Cancel): Pre-Signal-CancelConflictingOrders wird uebersprungen,
  wenn fuer den Markt eine Leiter aktiv ist – zerschiesst die Leiter-Order nicht.

Tests: 8 neue Integrationstests (SellLadderService ueber gemockten IClobClient):
atomarer/paralleler Claim, Waisen-Schutz, Claim-Rueckgabe, Floor-Neuplatzierung,
Floor-Halten bei ruhender Order, Leiter-Ende bei gefuellter Position.
Verifikation: Build 0 Fehler, 215 Tests gruen, --smoke-ui ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 12:43:17 +02:00
RichardandClaude Opus 4.8 ad8f7b0d03 Slice 0 (Fable-Fixes): IClobClient-Seam fuer testbare CLOB-Interaktionen
Verhaltensneutrale Testinfrastruktur als Grundlage fuer Slice 1/2:
- IClobClient-Interface (Core) ueber die von Leiter/Reconciliation genutzten
  CLOB-Methoden (Place/CancelConflicting/GetOpenOrders/CancelOrder).
- PolymarketClobClient implementiert IClobClient (Signaturen unveraendert).
- DI-Seam im Modul: IClobClient -> PolymarketClobClient-Singleton.
- SellLadderService haengt jetzt an IClobClient (statische CalculateExactOrderAmounts
  bleibt am konkreten Typ).
- InternalsVisibleTo(PolyTrader.Tests) + FakeClobClient-Test-Double.

Verifikation: Build 0 Fehler, 207 Tests gruen, --smoke-ui Container-Aufbau ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 11:53:12 +02:00