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>
This commit is contained in:
Richard
2026-08-22 10:46:46 +02:00
co-authored by Claude Opus 5
parent 5ccd4f5f4e
commit cb58e094b6
4 changed files with 132 additions and 10 deletions
@@ -90,4 +90,67 @@ public class MarketRepositoryTests
Assert.Equal("Elections", market.Subcategory);
}
}
/// <summary>
/// Regression (2026-08-04): only Slug and Title were capped on the event upsert,
/// so a Polymarket event with an over-long Description made MySQL reject the whole
/// batch with "Data too long for column 'Description'" — aborting the entire market
/// sync, not just that one event. Every length-constrained Event field must be capped.
///
/// SQLite ignores varchar limits, so asserting "no exception" would prove nothing:
/// the assertions check the stored lengths instead.
/// </summary>
[Theory]
[InlineData(true)] // event already exists → update branch
[InlineData(false)] // new event → insert branch
public async Task AddOrUpdateEventsAsync_CapsAllLengthConstrainedFields(bool eventAlreadyExists)
{
using var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseSqlite(connection)
.Options;
using (var setup = new AppDbContext(options))
{
setup.Database.EnsureCreated();
if (eventAlreadyExists)
{
setup.Set<Event>().Add(new Event
{
Id = 1, Platform = PlatformType.Polymarket, PlatformEventId = 99L,
Slug = "existing", Title = "Existing", Description = "short"
});
setup.SaveChanges();
}
}
using (var ctx = new AppDbContext(options))
{
var repo = new MarketRepository(ctx);
await repo.AddOrUpdateEventsAsync(new[]
{
new Event
{
Platform = PlatformType.Polymarket,
PlatformEventId = 99L,
Slug = new string('s', 900),
Title = new string('t', 1500),
Description = new string('d', 6000),
ImageUrl = "https://x/" + new string('i', 2000),
Tags = new string('g', 2000)
}
});
}
using (var assertCtx = new AppDbContext(options))
{
var stored = await assertCtx.Set<Event>().SingleAsync(e => e.PlatformEventId == 99L);
Assert.Equal(512, stored.Slug.Length);
Assert.Equal(1024, stored.Title.Length);
Assert.Equal(4096, stored.Description!.Length);
Assert.Equal(1024, stored.ImageUrl!.Length);
Assert.Equal(1024, stored.Tags.Length);
}
}
}