M1: pure normalization engine + default seed

Infrastructure-free normalization engine in Core dispatching on MeterMode:
- Cumulative/Generation counters: register deltas, first-reading baseline (Haus 411,
  Auto 3755), meter swaps (water …861→2 reconciles to 12 via boundary registers OR an
  explicit amount override), counter resets, anomaly-guarded decreases.
- RuntimeCounter: Δhours × rate (fixed/empirical).
- ConsumableBalance: tank level-Δ + deliveries → consumption, cm→litre calibration;
  delivery-only rows before the first dipstick emit nothing.
- DirectDelta, and Virtual meters via a small safe arithmetic evaluator (Netz Einsparung
  = Haus − Netz, Eigenverbrauch = Erzeugung − Einsparung) — data-driven, not hardcoded.
- DatabaseSeeder: default energy types, cost categories, base settings (idempotent).

24 Core unit tests + 4 integration tests green.

Claude-Session: https://claude.ai/code/session_01WujdMtMJPbxDpDnMeK22rr
This commit is contained in:
2026-07-13 11:12:03 +02:00
parent 48a7f5a825
commit d972f67bad
21 changed files with 1121 additions and 1 deletions
+2 -1
View File
@@ -78,7 +78,8 @@ static async Task MigrateDatabaseAsync(WebApplication app)
await using var scope = app.Services.CreateAsyncScope();
var db = scope.ServiceProvider.GetRequiredService<MeterVaultDbContext>();
await db.Database.MigrateAsync().ConfigureAwait(false);
Log.Information("Database migrations applied");
await DatabaseSeeder.SeedAsync(db).ConfigureAwait(false);
Log.Information("Database migrations applied and defaults seeded");
}
/// <summary>Exposed for WebApplicationFactory-based integration tests.</summary>