fix(backend): declare LastIngestAt in the SessionsIndex manifest

bbc7a1d8 stamped LastIngestAt into IncrementSessionEventCountAsync's merge
entity intending it as Sessions-only ("deliberately not mirrored"), but that
same entity flows through SyncSessionIndexAsync into the index merge — the
field was already landing in SessionsIndex on every ingest batch, just
undeclared. The fail-soft drift guard has been warning ~1,200x/h in prod
since the 08-20 deploy, and a StartedAt-shift full rebuild would silently
drop the column, making index-served session reads lose lastIngestAt that
Sessions-served reads carry.

Declare it properly instead of suppressing: ConditionallyProjected in
SessionIndexFieldManifest, projected in BuildSessionIndexEntity (read side
MapToSessionSummary already handled it), sample value pinned in the
bidirectional manifest tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Oliver Kieselbach
2026-08-21 01:54:34 +02:00
parent 2e20476559
commit 7e7b6f8086
3 changed files with 9 additions and 0 deletions
@@ -90,6 +90,7 @@ public class SessionIndexFieldManifestTests
["DiagnosticsBlobName"] = "diag-0001.zip",
["DiagnosticsBlobDestination"] = "Hosted",
["LastEventAt"] = new DateTimeOffset(StartedAt.AddMinutes(44)),
["LastIngestAt"] = new DateTimeOffset(StartedAt.AddMinutes(46)),
["ResumedAt"] = new DateTimeOffset(StartedAt.AddMinutes(10)),
["StalledAt"] = new DateTimeOffset(StartedAt.AddMinutes(20)),
["AvgApiLatencyMs"] = 513.5,
@@ -78,6 +78,7 @@ namespace AutopilotMonitor.Functions.Services
"DiagnosticsBlobName",
"DiagnosticsBlobDestination",
"LastEventAt",
"LastIngestAt",
"ResumedAt",
"StalledAt",
"AvgApiLatencyMs",
@@ -225,6 +225,13 @@ namespace AutopilotMonitor.Functions.Services
if (lastEventAt.HasValue)
indexEntity["LastEventAt"] = EnsureUtc(lastEventAt.Value);
// Server-frame ingest stamp (IncrementSessionEventCountAsync merges this on every
// batch, so the index already carries it) — must be in this superset or a
// StartedAt-shift full upsert drops it and index-served reads lose the field.
var lastIngestAt = sessionEntity.GetDateTimeOffset("LastIngestAt")?.UtcDateTime;
if (lastIngestAt.HasValue)
indexEntity["LastIngestAt"] = EnsureUtc(lastIngestAt.Value);
var resumedAt = sessionEntity.GetDateTimeOffset("ResumedAt")?.UtcDateTime;
if (resumedAt.HasValue)
indexEntity["ResumedAt"] = EnsureUtc(resumedAt.Value);