90 Commits
Author SHA1 Message Date
RichardandClaude Opus 5 c75edfe841 Fortschrittsuebersicht an den Kopf der Roadmap
Stufe 0 und 1 sind abgeschlossen. Die Tabelle haelt fest, wo es weitergeht -
und dass Stufe 2 an einem Linux-System haengt, das bisher nicht zur Verfuegung
stand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 14:12:43 +02:00
RichardandClaude Opus 5 97756f24b8 Roadmap 1.1: nach main gebracht, zehn Feature-Zweige entfernt
main war als Fast-Forward auf feature/linux-net10 zu ziehen; beide stehen jetzt
auf 402c372. Vor dem Push gegen einen vollstaendigen Rebuild geprueft:
warnungsfrei, 126 Tests gruen.

Die zehn Feature-Zweige der Analytik- und Portierungsarbeit sind lokal und auf
origin geloescht. Neun waren restlos in main enthalten (rev-list einzeln
geprueft). Der zehnte, fix-event-description-truncation, nur inhaltlich: sein
Fix und sein Regressionstest stecken seit cb58e09 in main, der Commit selbst
wurde nie gemergt - der Unterschied beschraenkte sich auf den Kommentartext und
ein static. Damit das Loeschen nichts vernichtet, haelt ihn jetzt der Tag
archiv/fix-event-description-truncation (8a8a353) fest.

feature/linux-net10 bleibt vorerst stehen und ist mit main identisch.

STATUS.md und ROADMAP.md entsprechend nachgezogen: Zweig-Uebersicht, Build gilt
jetzt als warnungsfrei, und die drei bestimmenden offenen Punkte sind neu
sortiert - der Linux-Erstlauf ist jetzt der groesste Block, der geloeschte
API-Schluessel nur noch der Hinweis, dass die KI-Analyse bis zum Hinterlegen
eines neuen Schluessels ruht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 14:11:56 +02:00
RichardandClaude Opus 5 402c372060 Wartungshinweis zu TruncateEventStrings aus dem Fix-Branch uebernommen
Der Kommentar auf dem Branch fix-event-description-truncation hielt fest, dass
die Methode mit den HasMaxLength-Aufrufen in AppDbContext synchron bleiben muss.
Genau das ist die Falle, die den Bug ausgeloest hat - der Hinweis gehoert an die
Methode. Damit ist der Branch auch inhaltlich restlos aufgegangen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 14:08:58 +02:00
RichardandClaude Opus 5 55daa2c9de Roadmap 0.1, 1.2 und 1.3: Key raus, Build warnungsfrei, Backfill eingegrenzt
0.1 OpenRouter-Schluessel aus appsettings.json entfernt. Laut Nutzer war er
bereits inaktiv, eine Rotation beim Anbieter also nicht mehr noetig. Das Feld
bleibt leer stehen, mit Hinweis daneben: der Schluessel gehoert in die
Umgebungsvariable OpenRouter__ApiKey, die ohnehin Vorrang hat.

Damit die Anwendung ohne Schluessel sauber laeuft, steigt OpenRouterApiClient
jetzt frueh aus, statt zu senden. Vorher haette jeder Analyseversuch einen 401
erzeugt - der als Error im Fehler-Stream des Deployment Centers gelandet waere,
worauf der Aufrufer die Fehlermeldung als JSON zu parsen versucht und einen
zweiten Fehler erzeugt haette. Der Zustand wird einmal als Warning gemeldet.
Die Konstante NotConfigured liegt im Interface, weil Application die
Infrastructure-Schicht nicht referenziert.

1.2 Alle acht Nullable-Warnungen behoben, der Build ist jetzt warnungsfrei.
Es waren durchweg Annotationsfragen, kein Verhalten aendert sich:
* TradeRepository (6x) - die Parameterliste nimmt bewusst null auf, damit
  nullable Spalten als SQL-NULL geschrieben werden. Jetzt List<object?>.
* TraderAnalyticsWorker - ThenInclude(o => o!.Market); der Lambda ist ein
  Ausdrucksbaum fuer EF und laeuft nie.
* PolymarketProvider - raw.Question ?? ""; TruncateMarketStrings normalisierte
  den Wert einen Schritt spaeter ohnehin auf "".

1.3 Der Kategorie-Backfill holte den gesamten Marktbestand samt Event in den
Speicher und verwarf den Grossteil sofort wieder. Die Einschraenkung auf
Maerkte mit gefuellten Event-Tags steht jetzt in der Abfrage statt in der
Schleife. Ergebnis unveraendert.

Dabei einen eigenen Fehler in der Roadmap korrigiert: dort stand, dieser
Backfill laufe "bei jedem Start". Das stimmt nicht - er gehoert zu
RunRecalculateAllTradersAsync, der manuellen Wartungsaktion, die nur auf
Knopfdruck laeuft. Die Startzeit war nie betroffen. Die falsche Aussage stand
auch in STATUS.md und ist dort ebenfalls richtiggestellt.

Build warnungsfrei, 126 Tests gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 14:07:53 +02:00
RichardandClaude Opus 5 6975720dc6 Eine Roadmap statt neun Plandokumente; alte Plaene ins Archiv
Die offenen Punkte lagen ueber neun Dokumente verstreut, teils widersprechend,
teils mit Punkten, die laengst umgesetzt waren. ROADMAP.md fuehrt sie zusammen:
sechs Stufen, jeder Punkt gegen den Code geprueft.

Markierung ueber eine Legende, damit Konzepte nicht mit Aufgaben verwechselt
werden: dringend, eingeplant, Backlog, Konzept (durchdacht, aber bewusst nicht
eingeplant), liegt beim Nutzer, verworfen.

Stufen: 0 Sofort (OpenRouter-Key) - 1 Aufraeumen abschliessen (Merge nach main,
Nullable-Warnungen, Startup-Backfill) - 2 Portierung abschliessen (Linux-Erstlauf
und Verifikation, dann Deployment/CI) - 3 Analytik schaerfen (Strategie-
Klassifikation, Backtest-Harness, Track-Record im Score, Ranking) - 4 Daten-
haushalt (SQL des Nutzers) - 5 Ingest skalieren - 6 Monetarisierung vorbereiten.

Ein Anhang haelt fest, was geprueft und bewusst NICHT auf die Roadmap kam, damit
es nicht versehentlich wieder als Aufgabe auftaucht (Azuro/Limitless, die
Marketing-Seiten, Kaltarchiv, EF Core 10).

Archiv: FIXPLAN-DONE, FIXPLAN-G-Speicher, FIXPLAN-TODO, FIXPLAN-UI-Ranglisten,
UMSETZUNGSPLAN sowie ANALYSE-Linux-Portierung, PLAN-Linux-Portierung,
PLAN-Architektur-WebUI-Backend und PLAN-DatenIngest-Skalierung liegen jetzt
unter docs/archiv/ mit einer README, die jedes Dokument einordnet. Sie bleiben
als Begruendungs- und Detailquelle - die Roadmap nennt jeden Punkt knapp, die
Herleitung steht dort.

Dabei aufgefallen: die beiden nie gepflegten Plaene (Architektur, DatenIngest)
zeigten 40 offene Punkte, von denen die Haelfte umgesetzt war - Read/Control-
Split, /api/capabilities, CORS-Whitelist, Egress-Kanaele mit Cooldown und
Per-Kanal-Limiter, Ingest-Tiering. Nachgeprueft, abgehakt und mit Statusblock
eingeordnet, sonst waere das Archiv selbst eine Fehlerquelle.

Was dabei nur teilweise umgesetzt war, ist als Roadmap 5.3 aufgenommen
(Health-Statistik je Kanal, multi-homed pruefen, DB-Guard, Plausibilitaets-
pruefung), ebenso der nie durchgefuehrte Audit auf versteckte Writes in
Read-Endpunkten (6.1). Header-Rotation ist als verworfen markiert statt offen
zu bleiben: Verschleierung gegenueber Polymarket riskiert genau den Zugang, auf
dem das Projekt aufsetzt.

STATUS.md beschreibt jetzt nur noch den Ist-Stand und verweist fuer die offenen
Punkte auf die Roadmap, damit nichts doppelt gepflegt wird. CLAUDE.md nennt
beide Einstiege.

Build gruen, 126 Tests gruen, keine toten Links.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 18:46:00 +02:00
RichardandClaude Opus 5 1f230fe12c Fruehjahrsputz 2/2: Dokumentation auf den tatsaechlichen Stand gebracht
Die Plandokumente waren durchweg veraltet: 85 von 91 Punkten im
UMSETZUNGSPLAN standen auf offen, obwohl der Code sie enthielt, und in
FIXPLAN-UI-Ranglisten war keine einzige der 18 Aufgaben abgehakt, obwohl
beide zugehoerigen Commits laengst im Zweig stecken. Alles abschnittsweise
gegen den Code geprueft und die Haekchen gesetzt - mit Belegstellen, damit
die naechste Pruefung nicht wieder bei null anfaengt.

Neu: STATUS.md als Einstiegsseite - wo das Projekt steht, was fertig ist,
was offen ist, und was beim Aufraeumen bewusst stehengeblieben ist. CLAUDE.md
verweist darauf.

Nachgezogen:
* UMSETZUNGSPLAN.md - 66 Punkte abgehakt. Offen bleiben A4 (Strategie-
  Klassifikation), B2 (Secrets) sowie C3/D1/D2 (SQL-Arbeiten des Nutzers).
* FIXPLAN-UI-Ranglisten.md - abgeschlossen bis auf den als "Optional"
  markierten Pfeilrichtungs-Punkt.
* FIXPLAN-TODO.md - Teil D und F abgehakt; die Test-Baseline "16 gruen"
  auf die heutigen 126 korrigiert. Offen: F5 und zwei Tests aus F6.
* FIXPLAN-G-Speicher.md - G1 bis G4 als erledigt vermerkt, Baseline "39/1"
  korrigiert, Pfad auf die nicht mehr existierende WinFormsHost/appsettings.json
  richtiggestellt.
* docs/PLAN-Linux-Portierung.md - der Watchdog-Warnhinweis war ueberholt
  (DcHeartbeatService meldet an /api/watchdog/v1/ping). Abschnitt 11 empfahl
  noch, mit Phase 0 zu beginnen; jetzt benennt er Phase 5 und 6 als das, was
  wirklich aussteht. Die Randnotiz zu Zugangsdaten in LicenseGuard.cs ist
  gegenstandslos, die Datei laeuft ueber den Deploymentcenter.Client.

Zwei Befunde, die keine Aufraeumarbeit sind und deshalb nur dokumentiert
wurden - beide in STATUS.md Abschnitt 3:

1. In src/Predictalytics.Api/appsettings.json steht ein echter
   OpenRouter-API-Key im Klartext, versioniert seit 7045002. Nicht
   eigenmaechtig entfernt: ohne Rotation beim Anbieter bringt das nichts
   (die History behaelt ihn), wuerde aber die KI-Analyse abschalten.
   Der Schluessel muss zurueckgezogen und neu ausgestellt werden.
2. Die Portierung ist auf keinem Linux-System je ausgefuehrt worden. Die
   Verifikation vom 2026-08-08 lief unter Windows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 12:30:42 +02:00
RichardandClaude Opus 5 55011644a3 Fruehjahrsputz 1/2: toter Code, Altlast-Dateien, veraltete Verweise
Toter Code:
* ApiConfiguration.ConfigureApi (29 Z.) hatte keinen Aufrufer mehr.
  PredictalyticsHost baut die WebApplication seit Phase 2 selbst auf
  (Kestrel, CORS, Swagger, Static Files); ConfigureApi war der
  zurueckgebliebene Zwilling aus der Zeit davor.
* IAnalyticsService.GetTraitsAsync samt Implementierung. Die Methode gab
  konstant eine leere Liste zurueck; ihr eigener Kommentar hielt fest, dass
  sie ungenutzt ist. Der Endpunkt /api/traders/traits liest direkt aus dem
  DbContext und bleibt unveraendert.

Ungenutzte Paketreferenzen:
* Swashbuckle.AspNetCore aus Predictalytics.Api - wurde nur von ConfigureApi
  gebraucht; Swagger baut Hosting auf, das die Referenz selbst haelt.
* Microsoft.EntityFrameworkCore.Design aus Predictalytics.Worker - die
  Design-Time-Factory liegt in Infrastructure.
* Serilog.Sinks.File/.Console und Serilog.Formatting.Compact aus
  Predictalytics.Infrastructure - dort wird kein Logger konfiguriert, nur
  Serilog.Core/Events/Context verwendet. Die Sinks haengen am Hosting.

Altlast-Dateien:
* Spike/ - Projektdatei ohne eine einzige Quelldatei, net8.0, nicht in der
  Solution.
* query.csx - Ad-hoc-Abfrageskript von Juli mit fest eingetragenen
  DB-Zugangsdaten.
* NewDesign.zip (388 KB) und temp_new_design/ - Rohmaterial des
  Design-Entwurfs vom 15.07. Das Ergebnis liegt fertig in
  wwwroot/landing.html und wwwroot/docs.html.

Veraltete Verweise auf den entfernten WinForms-Host:
* CLAUDE.md nannte fuer die Release-Version eine csproj, die es nicht mehr
  gibt - sie steht seit der Zentralisierung in Directory.Build.props.
* docs/BETRIEB-Deploymentcenter.md: Anbindung und BuildInfo sitzen in
  Predictalytics.Hosting.
* docs/API.md: Die Aussage "ohne Authentifizierung" galt vor Phase 4. Jetzt
  mit Header X-Predictalytics-Key und den heutigen Methodennamen.
* Kommentare in Directory.Build.props, DevEndpoints.cs, PredictalyticsHost.cs.

Build ohne neue Warnungen (die 8 bestehenden CS86xx sind unveraendert),
126 Tests gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 12:19:46 +02:00
RichardandClaude Opus 5 cb58e094b6 Drei offene Bugfixes sichern (Stand vor dem Fruehjahrsputz)
Lagen unfertig im Worktree bzw. auf einem eigenen Branch und werden hier
gebuendelt, damit der Ausgangsstand vor der Aufraeumaktion festgehalten ist.

1. Event-Upsert kappte nur Slug und Title. Description, ImageUrl und Tags
   haben in AppDbContext ebenfalls ein HasMaxLength, wurden aber ungekuerzt
   geschrieben. Ein Polymarket-Event mit einer Beschreibung ueber 4096
   Zeichen liess MySQL den gesamten Batch mit "Data too long for column
   'Description'" ablehnen - damit brach der komplette Marktsync ab, nicht
   nur dieses eine Event. Ersetzt durch TruncateEventStrings, analog zum
   bereits vorhandenen TruncateMarketStrings. Regressionstest deckt beide
   Zweige ab (neues und bestehendes Event); uebernommen vom Branch
   fix-event-description-truncation, der damit aufgeht.

2. FingerprintSnapshotService warf bei jedem Trader, der in zwei
   Unterkategorien derselben Kategorie gehandelt hat. Der eindeutige Index
   ist TraderId+Category+Subcategory, ein ToDictionary auf die Kategorie
   allein kollidiert deshalb. Jetzt per GroupBy summiert.

3. DcErrorReporter meldete Zustandswechsel nur auf Debug-Ebene. Ein stumm
   abgeschalteter oder abgewiesener Fehler-Stream fiel erst auf, wenn im
   Deployment Center nach einem Absturz nichts ankam. Meldet jetzt auf
   Warning - das erreicht den DcErrorSink nicht (Error+) und erzeugt daher
   keine Rueckkopplung. Transportfehler werden nur beim ersten Mal
   gemeldet, damit ein Netzwerkaussetzer keine Warnung pro Fehler ausloest.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 10:46:46 +02:00
RichardandClaude Opus 5 5ccd4f5f4e UpdateService: Zugangsschutz, Plattform und sauberer Agent-Uebergang
Seit Deploymentcenter 2.4 liegt die Release-Ablage hinter HTTP-Basic-Auth mit
dem Lizenzschluessel als Zugangsdatum. Ohne ihn antwortet jeder Paketabruf mit
401. Predictalytics hat noch kein Release veroeffentlicht; nach UPGRADE.md
16.1 entsteht der Schutz fuer ein Produkt mit dem ersten Upload, der erste
ausgelieferte Build muss die Zugangsdaten also bereits mitbringen.

- DcUpdateService reicht licenseKey und platform (PlatformId.Current) an
  CheckForUpdateAsync und LaunchUpdateAgent weiter. Fehlt der Schluessel am
  Aufruf, greift LicenseClient.TryGetCachedKey - damit ist der Headless-Pfad
  mit abgedeckt.
- LaunchAgent startet ohne Lizenzschluessel gar nicht erst. Sonst schliesst
  sich die Anwendung, der Agent laeuft in einen 401, und zurueck bleibt eine
  geschlossene App ohne Update.
- restartPath und waitForCurrentProcess werden gesetzt: der Agent wartet auf
  das Ende dieses Prozesses, statt auf noch gesperrte Assemblies zu schreiben,
  und startet die Anwendung danach wieder. Ein null-restartPath ist dafuer
  nicht brauchbar - das SDK ersetzt ihn durch denselben ProcessPath -, beim
  Start ueber "dotnet App.dll" wird deshalb der Apphost aufgeloest.
- result.Unauthorized wird vor dem "ist aktuell"-Zweig behandelt. Bei 401
  setzt das SDK weder Error noch UpdateAvailable; die Pruefung meldete bisher
  "aktuell", waehrend in Wirklichkeit keine Updates mehr ankamen.
- Version zentral in Directory.Build.props, damit Hosting und Shell nicht
  auseinanderlaufen.
- run.sh setzt unter Linux das beim Entpacken verlorene Ausfuehrungsbit.
  .gitattributes haelt Shell-Skripte auf LF: mit core.autocrlf=true traegt die
  Arbeitskopie sonst CRLF, und CopyToPublishDirectory nimmt genau die ins
  Linux-Paket - dort scheitert der Start an "bad interpreter".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 09:43:44 +02:00
RichardandClaude Opus 5 6e8ccba258 Absicherung der Steuerendpunkte gegen die echte Datenbank verifiziert
Der in Phase 4 offen gebliebene Ende-zu-Ende-Nachweis ist nachgeholt. Geprueft
mit einem Wegwerf-Host, der ausschliesslich den Webserver startet - die Worker
blieben aus, weil parallel eine aeltere Instanz auf derselben Datenbank laeuft.
Zusaetzlich mit ApiSettings__ReadOnlyDatabase=true, sodass weder Migrationen
noch Seeding liefen.

Als externe Bindung diente 127.0.0.2: gilt der Pruefung als oeffentlich,
bleibt aber Loopback, oeffnet also nichts im Netz.

Ergebnis:
- localhost ohne Token: Steuerendpunkte 200, Swagger 200
- extern ohne Token:    Steuerendpunkte 404, Swagger 404, capabilities meldet
                        canControl false
- extern mit Token:     ohne Header 401, falscher Token 401, richtiger 200,
                        Swagger 404

Nebenbei verifiziert: Datenbankverbindung steht (37.803 MB), Web-UI und
Assets werden ausgeliefert, /api/dashboard liefert echte Daten
(151.094 Trader, 38.187.946 Trades).

Nur Dokumentation - keine Codeaenderung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 21:26:38 +02:00
RichardandClaude Opus 5 b175df6d3e Phase 4: Steuerendpunkte absichern, Kultur und Log-Pfad plattformfest
Die schreibenden API-Endpunkte waren ungeschuetzt. /api/capabilities meldete
zwar CanControl und AuthRequired aus der Konfiguration, erzwungen wurde davon
nichts: MapPredictalyticsControlEndpoints mappte Jobs, Trader-Steuerung und
Dev-Endpunkte bedingungslos.

Neu entscheidet die Bind-Adresse:
- localhost ohne Token: aktiv wie bisher, das Betriebssystem schuetzt
- localhost mit Token: aktiv, Token wird verlangt
- extern ohne Token: Endpunkte werden gar nicht gemappt, dazu ein Log.Error
- extern mit Token: Endpunkte verlangen X-Predictalytics-Key

Bewusst fail-safe herum, damit eine unbedachte Umstellung der Bind-Adresse
nicht stillschweigend die Steuerschnittstelle oeffnet. ApiTokenFilter
vergleicht laufzeitkonstant ueber CryptographicOperations.FixedTimeEquals.
Swagger ist bei externer Bindung abgeschaltet. /api/capabilities meldet jetzt
den tatsaechlichen Zustand statt einer Konfigurationsabsicht.

Weiter:
- RuntimeSetup.UseInvariantCulture als Erstes in beiden Startpfaden, damit
  die Systemlocale nicht auf Zahlen und Zeitstempel durchschlaegt
- Logverzeichnis neben den Einstellungen statt neben der Programmdatei,
  ueber PREDICTALYTICS_LOG_DIR uebersteuerbar
- CORS erlaubt immer die eigene Bind-URL, zusaetzliche Herkuenfte weiter
  ueber appsettings.json
- fehlendes Schwester-Repo Deploymentcenter scheitert mit verstaendlicher
  Meldung samt Klon-URL statt mit einem Fehler ueber eine fehlende csproj
- EgressPoolService: Linux-Verhalten von Socket.Bind kommentiert

24 neue Tests: IsPubliclyBound fuer Loopback-Schreibweisen, Leerwerte und
externe Adressen; dass leere Eingaben bestehende DB-Zugangsdaten nicht
ueberschreiben; und der Token-Filter gegen fehlende, falsche, zu kurze,
zu lange und abweichend geschriebene Token.

Build: 0 Fehler, 8 Warnungen (alle vorbestehend).
Tests: 124 bestanden, 0 Fehler, 1 uebersprungen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 21:13:49 +02:00
RichardandClaude Opus 5 0e01886640 WinForms-Host durch die Avalonia-Shell abgeloest
Merge von main: die dort entstandene Deployment-Center-Integration (Lizenz,
Heartbeat mit DB-Health-Check, Fehler-Stream, UpdateService) ist jetzt Teil
des plattformneutralen Kerns. Predictalytics.WinFormsHost ist entfernt.

Nach Predictalytics.Hosting gezogen:
- DcConfig, DcApiClient, DcErrorSink, DcHeartbeatService, DcUpdateService
  unveraendert - sie waren bereits plattformneutral
- DcErrorReporter ohne Application.ThreadException und MessageBox; der
  UI-Thread-Handler liegt jetzt beim Host und ruft ReportUiThreadException
- LicenseGuard/LicenseSession ohne Dialog und ohne WinForms-Timer. Neu:
  TryUseCachedAsync, ActivateAsync, StartPeriodicRevalidation ueber
  PeriodicTimer. Die Unterscheidung transienter Fehler und die Warnung vor
  ablaufender Gnadenfrist sind unveraendert uebernommen.
- Dc-Einstellungen von AppSettings nach PredictalyticsOptions; die
  Watchdog-Einstellungen entfallen
- DcErrorSink im LoggingSetup, Startbanner nutzt DcConfig.AppVersion

BuildInfo.targets wird jetzt von Predictalytics.Hosting importiert.

In der Avalonia-Shell nachgezogen:
- Menue Deployment Center mit Update-Suche und Lizenzstatus
- Einstellungsgruppe Deployment Center statt Watchdog, Update-Kanal als
  ComboBox, Server-URL nur zur Anzeige
- Heartbeat-Snapshot mit SELECT-1-Probe wie in der WinForms-Fassung
- Update-Pruefung still beim Start und interaktiv ueber das Menue, mit
  NotifyStopping vor dem Start des Update-Agenten
- Lizenzfenster wertet IsTransient aus: bei fehlender Serververbindung wird
  nicht behauptet, die Lizenz sei ungueltig
- TextBox.Watermark auf PlaceholderText (in Avalonia 12 veraltet)

Build: 0 Fehler, 8 Warnungen (alle vorbestehend).
Tests: 100 bestanden, 0 Fehler, 1 uebersprungen.
Verifiziert: --license-status meldet gueltig samt Gnadenfrist; die GUI
startet durch, prueft die Lizenz und laeuft gegen den UpdateService.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 21:07:13 +02:00
RichardandClaude Opus 5 168f4699e1 Deployment-Center-Integration im WinFormsHost
Loest die getrennten Server Watchdog (watchdog.mhdf.de) und LicenseLabrador
(license.mhdf.de) durch das Deployment Center (dc.mhdf.de) ab.

- DcConfig: einkompilierte Basis-URL und Produkt-Slug, Version aus BuildInfo
- DcApiClient: gemeinsamer HTTP-Zugang
- DcHeartbeatService: Heartbeat mit Metriken und DB-Health-Check
- DcErrorReporter/DcErrorSink: Error- und Fatal-Meldungen an den Fehler-Stream
- DcUpdateService: Update-Pruefung gegen den UpdateService
- LicenseGuard/LicenseDialog: Lizenzgate ueber /api/license/v1/validate,
  mit LicenseSession, Hardware-ID v2 und Unterscheidung transienter Fehler

WatchdogHeartbeatService entfernt, Betriebsdoku ersetzt.

Build: 0 Fehler.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 20:56:45 +02:00
RichardandClaude Opus 5 65b44e984e Lizenzsystem auf Deploymentcenter umgestellt
Predictalytics hing noch am abgeloesten LicenseLabrador (license.mhdf.de),
waehrend die Lizenzen inzwischen im Deploymentcenter (dc.mhdf.de) gepflegt
werden. Vor dem Umbau mit einem Wegwerf-Probelauf gegen den echten Client
abgesichert: Slug predictalytics, HWID v2 aus machine-guid, Server meldet valid.

Hosting/LicenseGuard.cs auf Deploymentcenter.Client umgeschrieben. Die
Aufteilung bleibt: plattformneutrale Pruefung im Hosting, interaktive
Aktivierung in den Hosts.

Gewinn fuer die Linux-Portierung:
- Hardware-ID v2 mit Quellen-Kaskade /etc/machine-id, dbus, DMI-UUID, MAC,
  Schluesseldatei; Container ueber DEPLOYMENTCENTER_HWID
- Der Rechnername steckt nicht mehr im Hash, Umbenennen verbraucht keinen
  Aktivierungsplatz
- Cache mit AES-256-GCM statt DPAPI, ohne stillen Klartext-Rueckfall unter
  Linux. Damit erledigt sich Punkt 3.2 Nr. 2 der Portierungsanalyse.
- XDG_CONFIG_HOME wird beruecksichtigt
- Keine Basic-Auth-Zugangsdaten mehr im Quelltext

Neue CLI-Schalter aus dem Integrationsleitfaden, ausgewertet vor jeder
Avalonia-Initialisierung: --license-status, --license-set-key,
--license-deactivate. Schluessel werden in der Ausgabe maskiert.

Die Lizenzfenster beider Hosts zeigen jetzt die Hardware-ID an, an die der
Server die Aktivierung bindet.

Build: 0 Fehler. Tests: 100 bestanden.
Verifiziert: --license-status meldet gueltig; die GUI startet vollstaendig
durch bis MainWindowViewModel.Start(), belegt durch die Logdateien.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 10:41:04 +02:00
RichardandClaude Opus 5 1efd23abe4 Phase 3: Avalonia-Bedienhuelle fuer Windows und Linux
Neues Projekt Predictalytics.Shell (Avalonia 12.1.1, net10.0) als
plattformuebergreifender Ersatz fuer den WinForms-Host. Setzt auf dem in
Phase 2 extrahierten Predictalytics.Hosting auf.

Oberflaeche:
- MainWindow mit Menue, Werkzeugleiste, Terminal-Tab, Einstellungen-Tab und
  Statusleiste. Die feste Fenstergroesse von 1886x1088 ist aufgeloest.
- Terminal als ListBox ueber ObservableCollection mit Einfaerbung nach
  Loglevel. Ringpuffer statt des bisherigen kompletten Leerens bei 500 Zeilen.
- Einstellungsansicht handgeschrieben als Ersatz fuer den PropertyGrid, den
  es in Avalonia nicht gibt: vier Gruppen, Passwortfelder, mehrzeiliges
  Textfeld fuer die Egress-Kanaele, ComboBox fuer den SSL-Modus. Gespeichert
  wird explizit statt bei jeder Einzeloperation.
- LicenseWindow ersetzt den WinForms-LicenseDialog.
- Dialogs.cs als schlanker Ersatz fuer MessageBox.Show, ohne Drittanbieter.

Headless-Modus (--headless) im selben Binary: fuer Linux-Server ohne
Desktop-Session. Die Argumentauswertung steht vor jeder Avalonia-
Initialisierung, sonst stirbt der Prozess ohne X11 bevor der Schalter greift.
Lizenz ueber PREDICTALYTICS_LICENSE_KEY statt Dialog, SIGTERM und SIGINT
ueber PosixSignalRegistration fuer sauberes systemd-Stop.
Exit-Codes: 0 planmaessig, 2 keine nutzbare Lizenz, 3 Fehler.

Plattformdetails: Schrift-Fallbackkette fuers Terminal, Avalonia.Fonts.Inter
als mitgelieferte UI-Schrift, UTF-8 fuer die Windows-Konsole im
Headless-Modus.

Die Avalonia-Basisklasse wird als global::Avalonia.Application angegeben:
innerhalb von Predictalytics.* loest der kurze Name auf den eigenen
Namespace Predictalytics.Application auf.

Build: 0 Fehler, 0 Warnungen. Tests: 100 bestanden.
Verifiziert: --headless laeuft bis zur Lizenzschranke und beendet sich mit
Exit-Code 2; GUI startet und zeigt das Lizenzfenster. Das Hauptfenster
konnte nicht geprueft werden, weil die hinterlegte Lizenz abgelaufen ist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 10:15:56 +02:00
RichardandClaude Opus 5 260dff1700 Phase 2: Plattformneutralen Hosting-Kern extrahiert
Neues Projekt Predictalytics.Hosting nimmt auf, was bisher im
windows-gebundenen WinFormsHost feststeckte, aber portabel ist:

- PredictalyticsHost (aus EmbeddedWebServer): Kestrel- und Worker-Lifecycle,
  Wartungsaktionen, DB-Groesse. Meldet Zustandswechsel ueber StateChanged.
- PredictalyticsOptions (aus AppSettings): ohne WinForms-Bezug. Die
  System.ComponentModel-Attribute sind plattformneutral und bleiben, damit
  das PropertyGrid Gruppen und Beschreibungen behaelt.
- LoggingSetup (aus Program.cs): Serilog-Aufbau, Terminal-Sink als optionale
  Action statt fester RichTextBox.
- LicenseGuard: GUI-frei. Periodische Revalidierung ueber PeriodicTimer statt
  WinForms-Timer, Abbruch ueber Callback statt Application.Exit. Der
  interaktive Dialogaufruf bleibt als LicenseGate im WinForms-Host.
- WatchdogHeartbeatService unveraendert verschoben.

Infrastructure: RichTextBoxSink -> DelegateSink umbenannt (war nie
WinForms-abhaengig, nur missverstaendlich benannt).

Einstellungen liegen jetzt unter %APPDATA%/Predictalytics bzw.
~/.config/Predictalytics statt neben der Programmdatei, mit einmaliger
Uebernahme aus dem alten Ort. Das Installationsverzeichnis ist unter Linux
ueblicherweise nicht beschreibbar.

wwwroot wird ueber einen Content-Eintrag neben die Programmdatei kopiert;
die frueheren Pfad-Heuristiken entfallen.

Hosting und WinFormsHost nutzen Microsoft.NET.Sdk statt Sdk.Web: der Web-SDK
globbt wwwroot automatisch als Static Web Asset und kollidiert mit dem
Content-Eintrag. WebApplication kommt ueber FrameworkReference.

Neu konfigurierbar (verhaltensgleiche Defaults): WebserverHost fuer die
Kestrel-Bind-Adresse, DbSslMode fuer die MySQL-Verschluesselung.

explorer.exe-Aufrufe durch ProcessStartInfo mit UseShellExecute ersetzt —
funktioniert unter Windows und Linux.

Build: 0 Fehler. Tests: 100 bestanden, 0 Fehler, 1 uebersprungen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 23:13:04 +02:00
RichardandClaude Opus 5 c9eff9f75e Phase 1: Solution auf .NET 10 und zentrale Paketverwaltung
Zielframework aller Projekte auf net10.0 (WinFormsHost: net10.0-windows),
zentral in Directory.Build.props statt je csproj. SatelliteResourceLanguages
ebenfalls zentralisiert.

Neue Directory.Packages.props mit ManagePackageVersionsCentrally: 21 Pakete,
Versionsangaben aus allen csproj entfernt.

EF Core bleibt bewusst auf 9.0.18 mit Pomelo 9.0.0. Pomelo hat keine
EF-Core-10-Version; 9.0.0 pinnt EntityFrameworkCore.Relational auf
[9.0.0, 9.0.999]. Die EF-9-Pakete zielen auf net8.0 und laufen auf der
net10.0-Runtime. Begruendung als Kommentar in Directory.Packages.props.

Uebrige Pakete auf aktuellen Stand: Swashbuckle 10.2.3 (ohne Bruchstellen),
Serilog 4.4.0, Microsoft.Extensions 10.0.10, Test-SDK 18.8.1, coverlet 10.0.1.

Sicherheits-Pin: SQLitePCLRaw 2.1.12 statt transitiv 2.1.10
(GHSA-2m69-gcr7-jv3q, High). Dazu CentralPackageTransitivePinningEnabled.

Build: 0 Fehler, 8 Warnungen (alle vorbestehend).
Tests: 100 bestanden, 0 Fehler, 1 uebersprungen, Testhost net10.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 22:54:18 +02:00
RichardandClaude Opus 5 f82a693818 Phase 0: UTC-Datumsauswertung korrigiert, Portierungsanalyse und -plan
Vorarbeiten fuer die Linux-/NET-10-Portierung (siehe docs/PLAN-Linux-Portierung.md).

DateTime.TryParse ohne DateTimeStyles liefert bei Z-Zeitstempeln Kind=Local und
rechnet in Lokalzeit um. An 13 Stellen in PolymarketProvider und LimitlessProvider
wurden so ISO-Zeitstempel der Plattform-APIs eingelesen, waehrend der Fallback
derselben Zuweisungen (DateTime.UtcNow) korrektes UTC schrieb - die Spalten
enthielten also gemischt verschobene und korrekte Werte. Auf einem Server mit
TZ=UTC haette derselbe Code andere Werte erzeugt als unter Windows.

Neuer Helfer Infrastructure/Helpers/DateParsing.cs kapselt das Parsen mit
InvariantCulture und AdjustToUniversal|AssumeUniversal; alle Fundstellen umgestellt.

Ausserdem:
- LimitlessProvider: Volume-Parsing auf InvariantCulture umgestellt
- EmbeddedWebServer: hartkodierten j:\-Absolutpfad als wwwroot-Fallback entfernt

Ein Backfill der Altdaten erfolgt bewusst nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 22:49:11 +02:00
RichardandClaude Fable 5 aa19a89301 Lizenz-Endpoint auf HTTPS umgestellt (Aktivierung schlug fehl)
license.mhdf.de leitet inzwischen http->https um. .NET wandelt beim
Folgen eines Redirects ein POST in ein GET um; der Server antwortet auf
GET /validate mit 405. Das SDK wertet jeden Nicht-2xx-Status als
"Server unerreichbar", faellt in den Offline-Fallback und meldet
NoLicense statt des echten Grundes - die Aktivierung war damit auf
frischen Installationen ohne Cache unmoeglich.

Nebeneffekt der Korrektur: die BasicAuth-Credentials gingen bisher im
Klartext ueber die Leitung. DEPLOYMENT.md fordert ohnehin TLS.

Verifiziert mit geleertem Cache: Erstaktivierung und Revalidierung
liefern beide Valid.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 12:18:24 +02:00
Richard c12ab1b618 @
Integrate analytics feature stack with Watchdog/License host integration

Merges the full copytrading-analytics stack (UI fixes, insider feed, fingerprint
snapshot foundation, strategy-drift alarm, edge-freshness, smart-money co-movement
detection + graph clustering, copy-portfolio) with the WinFormsHost Watchdog
heartbeat + LicenseLabrador license gate. No file overlap between the two lines.
@
2026-08-03 23:08:05 +02:00
Richard be56eadcc5 @
#1 increment 2: cluster the co-movement graph + network visualization

Completes the smart-money discovery lever beyond the per-seed list:
- Pure CoMovementGraphBuilder (Application): links wallets by shared timely
  co-entries and clusters the graph via union-find (connected components).
- GET /api/co-movement/graph builds the graph over copy-relevant + insider
  wallets and weights each node by an "informed share" — how often the wallet
  entered before a big favorable price move (from stored price snapshots,
  graceful when absent). This is the "co-move before price moves" signal.
- UI: a new "Netzwerk" page rendering an SVG cluster graph (node size = score,
  color = cluster, gold ring = insider, green ring = informed leader);
  click a node opens the trader.
- Tests: min-edge-weight, window filtering, connected-component clustering.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-08-03 23:06:36 +02:00
Richard 2eaa67fae2 @
#4 Copy-portfolio: diversified master mix instead of single-score ranking

The leaderboard ranks single scores, but the top N can be three correlated
weather bots. Suggest a de-clumped set instead:

- Pure CopyPortfolioBuilder (Application): greedily picks high-scoring masters
  while enforcing a per-category cap and a max pairwise correlation; reports who
  was dropped for correlation vs the category cap.
- GET /api/portfolio/suggest?size=8&maxPerCategory=2&maxSimilarity=0.6 builds the
  position-overlap similarity (signed market sets) among copy-relevant masters
  and runs the diversifier. New PortfolioEndpoints group.
- UI: a "Copy-Portfolio" nav page — the diversified picks with category, score,
  copyability, PnL and the pick reason, plus a funnel summary (candidates /
  dropped for correlation / dropped for category cap).
- Tests: top-score order, category cap, correlation drop, size limit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-08-03 19:45:35 +02:00
RichardandClaude Fable 5 725746d204 Watchdog-Integration gegen Produktivserver verifiziert und korrigiert
- Shutdown-Event sendet stopped_graceful statt stopping: der Server
  kennt "stopping" im Router, aber event_log.kind ist ein ENUM ohne
  diesen Wert. Folge war HTTP 500 nach dem Zustandswechsel, das Event
  fehlte in der Historie.
- Default-Source auf "Predictalytics" korrigiert (Schreibweise des
  bereits angelegten Monitors auf dem Server).

Heartbeat, Metrics-Payload, Lizenzvalidierung und der Startpfad ueber
den Cache sind end-to-end gegen die Produktivserver getestet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 17:42:02 +02:00
RichardandClaude Fable 5 3a82397651 Watchdog-Heartbeat + LicenseLabrador-Lizenzgate im WinFormsHost
Bindet die beiden neuen Betriebsprojekte an:

- WatchdogHeartbeatService: periodischer POST /api/heartbeat an
  watchdog.mhdf.de (Dead-Man's-Switch), stopping-Event beim Beenden,
  Konfiguration ueber AppSettings-Kategorie "Watchdog". Fehler sind
  best effort und beeintraechtigen die App nie.
- LicenseGuard + LicenseDialog: Lizenzpruefung vor dem Start der
  MainForm, 12h-Revalidierung zur Laufzeit, Checksum-Haertung.
  Produkt-Slug/Endpoint/Public-Key sind einkompiliert.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 12:12:54 +02:00
Richard 351e938769 @
#1 Smart-money co-movement detection (discovery increment 1)

The correlation endpoint was only pairwise + position-overlap based. Add timing-
based, one-to-many co-movement discovery: for a seed trader, find the wallets
that repeatedly enter the SAME outcomes within a time window — surfacing new
informed traders rather than just ranking known ones.

- Pure CoMovementCalculator (Application): ranks candidate wallets by shared
  co-entered markets; positive AvgLeadHours = the wallet tends to move BEFORE the
  seed (the informed-trader signal).
- GET /api/traders/{id}/co-movement?windowHours=48&minShared=3 (bounds the seed
  to its last 500 buys) + CoMovingWalletDto.
- UI: a co-movement card on the trader detail page listing the top related
  wallets with shared-market count and lead/lag (green when they move first).
- Tests: min-shared threshold + window filtering, lead sign, ranking order.

Next increment: cluster the co-movement graph + a visual; weight co-entries that
precede significant price moves. Endpoint is on-demand per seed for now.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-24 12:27:10 +02:00
Richard e5ce69793b @
#5 Edge-freshness: is a master edge current or stale?

Compares the recent out-of-sample window (last 60d) against the older one
(day 60-180) — both already produced per run by the analytics worker, so no
worker changes and no schema change.

- Pure EdgeFreshnessCalculator (Application): Fresh / Stable / Fading /
  Insufficient + a 0-100 freshness score. Fading when return/market drops past a
  threshold or a once-strong profit factor collapses below break-even.
- GET /api/traders/{id}/edge-freshness reads the two windows and computes it.
- UI: a colored edge-freshness badge on the trader detail page
  (🟢 frisch / 🟡 stabil / 🔴 verblasst) with the return delta and market counts.
- Tests: 5 scenarios (insufficient, fresh, return collapse, PF collapse, stable).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-24 11:44:23 +02:00
Richard b7bee86ed7 @
#3 Strategy-drift alarm: fire + surface drift off the fingerprint history

Turns the drift foundation into an actual alarm that protects copiers:
- New AlertType.StrategyDrift (severity 3).
- FingerprintSnapshotService.GetDriftedTradersAsync lists every master whose
  latest fingerprint drifted from its baseline.
- AlertService.EvaluateStrategyDriftAsync (run from EvaluateAlertsAsync) fires a
  StrategyDrift alert per drifted master, summarizing the changed dimensions.
  Drift is slow-moving, so alerts are de-duplicated per trader over a 7-day
  cooldown via new IAlertRepository.ExistsRecentAsync.
- UI: 📉 icon in the alert feed + a drift banner on the trader detail page
  (fetches /fingerprint-drift, lists the drifted dimensions).
- Test: drift alert fires once then dedups within the cooldown.

No schema change (reuses TraderFingerprintSnapshots + Alerts).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-24 09:50:42 +02:00
Richard b21da1c2c7 @
Fingerprint-snapshot foundation + strategy-drift calculator (#3/#5 groundwork)

TraderAnalytics is one row per trader, overwritten every recalculation, so there
is no history to detect strategy drift (#3) or edge fade (#5) against. Add the
missing time series:

- TraderFingerprintSnapshot entity (score, category concentration, conviction,
  P50/P90 sizing, hold duration, trades/week, category-mix JSON, trait-set JSON)
  + migration AddFingerprintSnapshots (indexed by TraderId, CapturedAt).
- FingerprintSnapshotService (Infrastructure): CaptureDueAsync snapshots every
  copy-relevant trader (CopytradingScore >= 40) at most ~once/day; wired into
  ScoringAndAlertsWorker. GetDriftAsync reads latest-vs-baseline drift.
- FingerprintDriftCalculator (pure, Application): flags score drop, concentration
  shift, sizing jump, conviction sign-flip, category-mix TVD, trait-set change.
- GET /api/traders/{id}/fingerprint-drift?baselineDays=14 read endpoint.
- Tests: drift calculator (4 scenarios) + capture service (copy-relevance,
  throttle, drift read).

This is the shared foundation both #3 (drift alarm) and #5 (edge freshness) build on.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-23 21:21:21 +02:00
Richard 2bec11d0a9 @
Rework insider feed: system-level InsiderWatch + dedicated view (no watchlist writes)

Watchlists will become per-user once the product is offered commercially, so the
system must not auto-add/remove traders there. Decouple insider tracking entirely:

- New system-owned entity InsiderWatch (TraderId unique, FirstDetectedAt,
  LastAlertedTradeAt) + IInsiderWatchRepository; migration AddInsiderWatch.
- AlertService.EvaluateInsiderWatchAsync now maintains InsiderWatch (not the
  watchlist): registers each possible_insider wallet, seeds the high-water mark
  at detection time, and fires one InsiderActivity alert per new trade. Dedup via
  LastAlertedTradeAt.
- Dedicated "Insider" view: GET /api/traders/insiders + InsiderDto + a new
  Insider-Radar page (sorted by market-surprise). Read-only, separate from watchlist.
- Revert the WatchlistEntry.LastInsiderAlertAt field + its migration (unapplied);
  drop the now-unused IWatchlistRepository.UpdateAsync.
- Tests updated to assert InsiderWatch registry (and that no WatchlistEntry is created).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-23 20:52:37 +02:00
Richard 8b9b34342f @
Insider-Follow feed: auto-watchlist possible-insider wallets + new-trade alerts

Makes the existing possible_insider trait actionable:
- New AlertType.InsiderActivity (severity 4).
- AlertService.EvaluateInsiderWatchAsync (run from EvaluateAlertsAsync every
  15 min): auto-adds every possible_insider wallet to the watchlist, then fires
  one InsiderActivity alert per new trade one of them places. These wallets
  trade rarely, so a single new trade is the strongest copy signal.
- Dedup + no history spam via WatchlistEntry.LastInsiderAlertAt (migration
  AddWatchlistLastInsiderAlertAt); a freshly auto-added wallet is baselined at
  AddedAt so backfilled trades never alert.
- Repo support: ITraderRepository.GetByTraitAsync, IWatchlistRepository.UpdateAsync.
- UI: distinct 👁 icon for insider alerts (💰 for large positions).
- Tests: auto-add-without-history-alert, alert-on-new-trade-with-dedup.

Migration auto-applies on startup (DependencyInjection.MigrateAsync).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-23 19:46:36 +02:00
Richard 295752d778 @
UI-U1/U2/U4/U5: dashboard showcases + server-side leaderboard sort

- U1: render the /api/traders/showcases sections on the dashboard as
  clickable curated leaderboard cards (red_flags visually accented).
- U2: loadTraders() now sends the sort key to the API (real top-N),
  take raised to 200; only name/platform stay client-sorted.
- U4: #tradersSort dropdown extended with calmar/conviction/profitfactor/
  pnl30d; currentSort synced before building the query.
- U5: fix empty-state colspan 11 -> 10 (table has 10 columns).

Includes FIXPLAN-UI-Ranglisten.md documenting the plan.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-23 17:35:49 +02:00
Richard d8c204995a @
UI-U3: server-side min-winrate/min-copyability filters

Add optional minWinRate/minCopyability params to GetTradersAsync so the
leaderboard min-value filters see the full pool instead of being applied
client-side to only the first page of results. Covered by a new
AnalyticsService test (three traders, both filters).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-07-23 15:56:58 +02:00
RichardandClaude Opus 4.8 02c5a4d6f4 Add showcase leaderboards endpoint + sortable trader list
- GET /api/traders/showcases: curated dashboard sections (copy-ready, smooth
  operators, rising stars, high conviction, specialists, insider watch, red
  flags), each encoding a selection funnel over the persisted analytics/traits.
  Pure ShowcaseBuilder holds the ranking logic (+6 unit tests).
- GET /api/traders?sort=: leaderboard sort keys (pnl, pnl30d, winrate,
  copytrading, calmar, conviction, profitfactor) over the loaded set.
Read-only, persisted-data-only (public-tier safe). 76 tests, 1 skip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 09:43:11 +02:00
RichardandClaude Opus 4.8 eaccdadddf H2: strategy-fingerprint metrics (conviction/sizing edge + category concentration)
Two deeper analyses, both pure from existing data (no new API cost):
- ConvictionEdgePct: return% of the biggest-bet third minus the smallest-bet
  third of closed markets. Positive => sizing carries information (copy
  size-weighted); negative => overbets losers (red flag). CalculateMarketWinRates
  now emits per-market (invested, returnPct) pairs consumed by
  StrategyMetricsCalculator.ComputeConvictionEdge.
- CategoryConcentration: Herfindahl index of category volume shares
  (specialist vs generalist), from the category-performance dict.
Stored on TraderAnalytics, exposed on TraderDetailDto. Migration
AddStrategyFingerprintMetrics. +7 unit tests (70 total, 1 skip).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 09:17:58 +02:00
RichardandClaude Opus 4.8 dcac62165e H1: risk-adjusted return metrics (equity-curve smoothness = copyability)
New RiskMetricsCalculator (pure) derives max drawdown (USD), daily-PnL volatility
and longest losing streak from the trader's TraderDailySnapshot equity curve; the
PnL engine computes them each recalc and stores them on TraderAnalytics (+ computed
ReturnOverMaxDrawdown, Calmar-like). Two traders with identical final PnL but a
smoother path are very differently copyable — this captures that. Exposed on
TraderDetailDto. Migration AddRiskAdjustedMetrics. +5 unit tests (63 total, 1 skip).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 09:14:15 +02:00
RichardandClaude Opus 4.8 be1b90b556 Fix Aggregated-tier mutable-bucket vs checkpoint bug
The Aggregated ingest tier bucketed trades by hour incl. the current, still-growing
hour, then upserted via ON DUPLICATE KEY UPDATE (mutable rows). The PnL engine
checkpoints positions by row Id, so a bucket that keeps growing after being applied
had its later growth silently skipped (Id <= LastAppliedTradeId).

Extract the duplicated aggregation logic from PollingWorker + TradeHistoryWorker into
TradeAggregation.AggregateCompletedHours, which only aggregates COMPLETED hours; the
current hour is deferred (re-fetched next cycle) so every persisted aggregate is
immutable. +3 unit tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 08:57:46 +02:00
Richard 3ed0b4df27 D3: Implement IngestMode classification, weekly biopsy, SnapshotOnly bypass, and Aggregated import grouping 2026-07-19 17:23:19 +02:00
Richard 6fd7e563f4 G3 & G4: Map UsdcSize, OutcomeIndex, compute Category ROI and add migration 2026-07-19 12:35:03 +02:00
Richard 8a39b912a6 G1 & G2: Storage Governor and Aggregated retention pruning 2026-07-19 10:56:12 +02:00
Richard 7045002ca3 WebUI Redesign and Component 1: category mapper fixes 2026-07-19 10:51:07 +02:00
RichardandClaude Opus 4.8 c3e66d6cca Add FIXPLAN Teil G (storage budget + per-category edge) for Gemini 3.5 Flash
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 10:19:28 +02:00
RichardandClaude Opus 4.8 04596f95a6 Add Teil F (structural category-detection fix) to FIXPLAN-TODO
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 20:20:05 +02:00
Richard 16431f38a5 feat: implement Part D and E from FIXPLAN
- D1/D2/D2c: Added TraderTraits entity, TraderTraitCalculator, Market Return Metrics (MedianWin, AvgWin, etc.), and trait filters
- D3: Implemented HF-Trader Tiering via IngestMode (Full, Aggregated, SnapshotOnly) and updated TradeHistoryWorker to respect tiers
- E1-E5: Added MasterStatus to Trader, TraderWindowMetrics for rolling analytics, Fingerprint metrics (PriceBandProfile, P50/P90), Copyability aggregates (Volume, Drift, Edge)
- E6: Implemented GET /api/traders/{id}/profile and GET /api/traders/correlation
- Replaced FIXPLAN-2026-07-09.md with FIXPLAN-TODO.md and FIXPLAN-DONE.md
- Cleaned up API docs and plan to use generic terms (removed hardcoded PolyTrader references)
- Added respective EF Core Migrations
2026-07-14 09:04:31 +02:00
RichardandClaude Fable 5 a1fcb4ace5 API audit: expose 7d/24h windows, remove broken repair-db, add API docs
- TraderDetailDto now exposes PnL7d/WinRate7d/PnL24h/WinRate24h and
  CurrentBalance — the engine has computed these all along but the API
  never delivered them.
- Removed POST /api/dev/repair-db: its raw SQL referenced non-existent
  columns/tables (Trades.Type/Payout, Traders.LastPositionsUpdatedAt,
  table "Jobs") and would have deleted ALL TraderPositions including
  pruned-history conserves. The supported repair path is the WinForms
  "Recalculate All Traders" action.
- Swagger tags for Jobs and Dev groups; full endpoint reference in
  docs/API.md (kept generic — external consumers like PolyTrader adapt
  to our API, not vice versa).
- FIXPLAN Teil E: master-selection gap analysis as generic extensions
  (profile endpoint, out-of-sample window metrics, price-band profile
  with per-band win rate, stop-loss ratio, copyability aggregates with
  category fees, correlation endpoint, martingale trait).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 18:34:02 +02:00
RichardandClaude Fable 5 28e112f128 Add per-market win/loss return metrics (D2c) to FIXPLAN Teil D
Win rate alone hides the payoff profile: an arb grinder (95% wins at +2%)
and a longshot holder (25% wins at +400%) need entirely different copy
strategies. D2c adds median+avg return of won AND lost closed markets,
profit factor, UI cards, and two derived traits (thin_margin_wins,
high_payoff_wins). Median leads (outlier-robust), the loss side is
mandatory — high win rates with rare total losses (resolution farming)
are exactly what the win rate alone obscures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 10:30:28 +02:00
RichardandClaude Fable 5 916c3e17a6 Add trait filter spec and possible_insider detection to FIXPLAN Teil D
- Trait filtering is now a binding requirement: trait query parameter on
  GET /api/traders (EXISTS-based), GET /api/traits with counts, dropdown
  plus clickable chips in the UI.
- New trait possible_insider (D2b): detection via market-surprise
  likelihood under market prices (won longshots count, won favorites do
  not), with base filters (rare, large stakes, resolution farmers
  excluded) and a v2 roadmap (buys-before-news timing, one-shot wallets,
  topic concentration, urgency/slippage, niche markets).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 14:52:39 +02:00
RichardandClaude Fable 5 d2f3ec2bd0 Fix category mapping and TotalTrades drift, plan traits/tiering (Teil D)
- MarketCategoryMapper: classify from question text (the Gamma /markets
  endpoint delivers neither category nor event tags, so on-demand markets
  had no signal at all), match short tokens on word boundaries ("eth" no
  longer hits inside "whether", "pop" not inside "popular"), widen the
  keyword lists across all categories.
- UpdateMarketFields: never overwrite a tag-derived category with an
  uninformative "Other" from the on-demand path.
- PositionPnLEngine: sync Trader.TotalTrades to the actual replayed row
  count — the worker-side increment counters drift (INSERT IGNORE,
  deletions, historic imports) and produced Trades30d > TotalTrades.
- Tests: 14 new (mapper classification + word-boundary regression,
  TotalTrades sync + Trades30d invariant, category update guard via
  SQLite) — suite now 32 green + 1 skip.
- FIXPLAN Teil D for the larger rebuilds (AggregatedCount column,
  TraderTraits heuristics, IngestMode tiering for ultra-HF traders).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 14:09:12 +02:00
RichardandClaude Fable 5 940a99fec2 Retry analytics on concurrent-modification conflicts instead of erroring
The reconciliation worker resets position checkpoints via bulk UPDATE while
the analytics worker saves recalculated positions for the same trader —
MySQL then rejects the stale save ("Record has changed since last read").
The engine run is now retried once with a fresh context (re-reading the
concurrent change); if it still collides, it logs a warning and lets the
next cycle pick the trader up again (LastAnalyzedAt stays unset).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 18:48:51 +02:00
RichardandClaude Fable 5 850c47a404 Fix embedded-server endpoint drift, add Recalculate All Traders button
- Shared ApiConfiguration.MapPredictalyticsEndpoints() used by both the
  standalone API and the embedded WinForms Kestrel server: the embedded
  host was missing /api/watchlist and /api/dev (empty watchlist page),
  the standalone host was missing /api/search.
- New Development menu action "Recalculate All Traders": backfills
  ResolutionOutcome from snapped outcome prices, wipes derived analytics
  (snapshots, category stats, rebuildable positions), zeroes aggregates
  and marks every trader for re-analysis. Raw trades untouched.
- Static files now served with Cache-Control: no-cache in both hosts,
  plus ?v= cache-buster on app.js/style.css (stale browser JS masked
  earlier UI fixes).
- Watchlist hardened: endpoint null-safe, real Analytics.CopytradingScore,
  Platform field; repository includes Trader.Analytics; page shows a
  visible error row instead of staying silently blank.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:58:10 +02:00
Richard 1787422243 Fix: Implement FixPlan part A9, A10, B 2026-07-10 12:04:27 +02:00
Richard 44f48284a2 Fix 10 critical bugs in Engine, Retention, Reconciliation and API 2026-07-09 19:37:02 +02:00
Richard 21da1e867f Add Fable's Stufe A invariant tests 2026-07-09 18:42:31 +02:00
Richard 7964194e9e Implement WinRate, Bankroll, Positions UI and add Trades30d to Analytics 2026-07-09 12:44:32 +02:00
Richard 3b11b71188 Add EF migration for CopytradingScores 2026-07-08 20:40:48 +02:00
Richard 651f8f3ad1 Add Analyze Backlog button to WebUI 2026-07-08 20:18:03 +02:00
Richard a4acd23a60 Fix worker pagination, apply Analytics fixes, add analyze backlog endpoint 2026-07-08 20:13:52 +02:00
Richard 882226c6c6 Add unit tests for Engine and Scoring fixes 2026-07-07 18:38:23 +02:00
Richard 4eb0d99b4e Fix Estimator scoring and PnL engine cashflow 2026-07-07 18:30:20 +02:00
Richard 8d056653f9 Fix EF Core ExecuteSqlRawAsync DBNull mapping error by using null instead of DBNull.Value 2026-07-07 13:06:27 +02:00
Richard 3105f6f28e Use raw SQL INSERT IGNORE for TradeRepository.AddRangeAsync to prevent DbUpdateException on duplicates 2026-07-07 13:01:31 +02:00
Richard 2375a193e6 Fix EF Core missing OrderBy warning 2026-07-07 12:32:08 +02:00
Richard 5ca50836a9 Fix DbUpdateException in TradeRepository and Polymarket API 400 on max offset 2026-07-07 12:23:37 +02:00
Richard 1485c7cba9 Fix TradeReconciliationWorker: Fetch missing markets from API on demand before linking orphaned trades 2026-07-07 12:05:00 +02:00
Richard d24f0ecc2e Fix WinRate 0% bug: Optimize TradeReconciliationWorker with bulk SQL and reset Trader analytics flag 2026-07-07 10:56:52 +02:00
Richard 910d25159a Add tracking for analyzed traders and add crawling configuration to appsettings.json 2026-07-07 09:45:51 +02:00
Richard 2c7c643fdb Fix styling, job endpoints, and infinite worker loops 2026-07-07 09:21:37 +02:00
Richard 10eefd3546 Fix API offset limit 400 Bad Request, implement requested UI/UX improvements 2026-07-06 22:34:33 +02:00
Richard fb703b6c81 feat: Jobs infrastructure, endpoints, UI and worker prioritization 2026-07-06 19:58:23 +02:00
Richard 33a52ed173 fix: Polymarket API offset limit crash in CopytradingEstimator 2026-07-06 13:01:06 +02:00
Richard a564c016bb feat: Implement copytrading analytics and update WebUI
- Add v4 Tape-based CopytradingEstimator (Clustering, MAE, Tape Fills)
- Add CopytradingBacktestHarness (Walk-Forward testing, Shrinkage, LCB ranking)
- Add EF Core Migrations for FollowerFillPrice and Scoring fields
- Update WebUI: Fix Trader Detail tab layout blowout
- Update WebUI: Redesign Trader Detail menubar
- Update WebUI: Display separate Quality and Copyability metric cards
- Update WebUI: Add 'Highly Copyable' filter to Trader List
2026-07-06 11:55:38 +02:00
Richard c0c598b86a Fix Trader Detail Page layout constraint and improve menu bar 2026-07-05 20:23:16 +02:00
Richard 689ba45533 Fix index drop order in AddTradeContextAndSubcategory migration to satisfy MySQL FK constraints 2026-07-05 20:16:45 +02:00
Richard d3fac35785 Fix EF Core shadow property mapping bug for TraderAnalytics 2026-07-05 20:14:23 +02:00
Richard dc0b67deaa test: fix AnalyticsServiceTests by mocking missing dependencies and adding moq 2026-07-05 19:46:21 +02:00
Richard 3f6f8fc17d feat: rebuild trader detail UI with tabs and manual recalculate button 2026-07-05 19:04:35 +02:00
Richard b5dfa6bb1b refactor: use existing TradeContextEnrichmentWorker for TradeContext and Slippage calculations 2026-07-05 19:03:04 +02:00
Richard 0b799123db feat: prioritize trader analytics via LastAnalyzedAt and add force-analyze endpoint 2026-07-05 18:58:33 +02:00
Richard c38b4d498f feat: add TradeContext, Subcategory and LastAnalyzedAt 2026-07-05 18:56:18 +02:00
Richard 8f6bce23f3 fix: filter unmapped trades from UI display 2026-07-05 15:01:54 +02:00
Richard d533374ced fix: remove TestSql.cs that caused build errors 2026-07-05 14:30:45 +02:00
Richard c81e5638b5 fix: Resolve EF Core shadow property issue and increase migration timeout 2026-07-05 14:22:16 +02:00
Richard e9e9ce0d5a feat: Add category performance, update WebUI and OpenRouter integration, fix bugs 2026-07-05 14:13:16 +02:00
Richard d102af2965 Enhance UI, add AI integration, improve logging and database stats 2026-07-04 21:11:31 +02:00
Richard 7a44914d9d Implement B4: Add Predictalytics.Application.Tests project with unit tests for PositionPnLEngine and AnalyticsService 2026-07-03 11:22:43 +02:00
Richard f8c8230d99 Implement A3, A4, A5, B3: Add MarketOutcomePriceSnapshot, implement Polymarket CLOB prices-history endpoint, improve strategy classification, introduce CopytradingScore, and decouple/optimize scoring pipeline into a separate worker 2026-07-03 11:20:28 +02:00
Richard e994e1ce72 Implement A1, A6, A2: Add TraderPosition entity, PositionPnLEngine (Average-Cost-Method), Market-level WinRate, and integrate with TraderAnalyticsWorker 2026-07-03 11:16:42 +02:00
Richard 5fe7ab63ac Fix B6: Market concurrency lock, watchlist exclusion from cleanup, optimized trade ID deduplication query, and TradeHistoryWorker sync logic 2026-07-03 11:10:53 +02:00
Richard 434c631290 Document additional bugs/perf issues found in second review pass
Added B6 to UMSETZUNGSPLAN.md: unbounded MarketSyncWorker re-sync of all
closed markets, watchlisted traders not exempt from auto-cleanup deletion,
full trade-history load in GetKnownPlatformTradeIdsAsync, a race condition
in MarketRepository.AddOrUpdateAsync under concurrent access, and an
early-break assumption in TradeHistoryWorker that isn't applied consistently.

No functional code changed yet — these are earmarked for Phase 2 (B3-adjacent).
2026-07-03 10:37:06 +02:00
Richard 340bfdaa82 B1: EF Core migrations baseline validated against real dev DB
- Design-time AppDbContextFactory now builds its connection string via
  MySqlConnectionStringBuilder from PREDICTALYTICS_DB_* env vars instead of a
  hardcoded local default, so no secret needs to live in source/config to run
  migrations against any target database.
- InitialBaseline migration applied end-to-end against a fresh dev MySQL DB
  and confirmed via `dotnet ef migrations list`.
2026-07-03 10:30:13 +02:00
Richard afb251acfc Initial commit: Predictalytics solution
Clean Architecture .NET 8 solution (Domain/Application/Infrastructure/Api/Worker/WinFormsHost)
for analyzing Polymarket traders for copytrading/strategy-replication candidates.

Includes EF Core InitialBaseline migration and DB secrets removed from source/config
in preparation for version control.
2026-07-01 19:53:29 +02:00