diff --git a/src/Agent/AutopilotMonitor.Agent/buildcounter.txt b/src/Agent/AutopilotMonitor.Agent/buildcounter.txt
index d50bf78a..cb93c35b 100644
--- a/src/Agent/AutopilotMonitor.Agent/buildcounter.txt
+++ b/src/Agent/AutopilotMonitor.Agent/buildcounter.txt
@@ -1 +1 @@
-835
+837
diff --git a/src/Backend/AutopilotMonitor.Functions/Functions/Ingest/IngestEventsFunction.Helpers.cs b/src/Backend/AutopilotMonitor.Functions/Functions/Ingest/IngestEventsFunction.Helpers.cs
index 31fd7148..1291fbcc 100644
--- a/src/Backend/AutopilotMonitor.Functions/Functions/Ingest/IngestEventsFunction.Helpers.cs
+++ b/src/Backend/AutopilotMonitor.Functions/Functions/Ingest/IngestEventsFunction.Helpers.cs
@@ -128,7 +128,12 @@ namespace AutopilotMonitor.Functions.Functions.Ingest
if (evt.Data != null)
{
if (evt.Data.ContainsKey("doFileSize") && long.TryParse(evt.Data["doFileSize"]?.ToString(), out var doFs))
+ {
summary.DownloadBytes = Math.Max(summary.DownloadBytes, doFs);
+ summary.DoFileSize = doFs;
+ }
+ if (evt.Data.ContainsKey("doTotalBytesDownloaded") && long.TryParse(evt.Data["doTotalBytesDownloaded"]?.ToString(), out var doTotalDl))
+ summary.DoTotalBytesDownloaded = doTotalDl;
if (evt.Data.ContainsKey("doBytesFromPeers") && long.TryParse(evt.Data["doBytesFromPeers"]?.ToString(), out var doPeers))
summary.DoBytesFromPeers = doPeers;
if (evt.Data.ContainsKey("doBytesFromHttp") && long.TryParse(evt.Data["doBytesFromHttp"]?.ToString(), out var doHttp))
diff --git a/src/Backend/AutopilotMonitor.Functions/Functions/Metrics/GetGeographicMetricsFunction.cs b/src/Backend/AutopilotMonitor.Functions/Functions/Metrics/GetGeographicMetricsFunction.cs
index 0abca3c0..46d1d461 100644
--- a/src/Backend/AutopilotMonitor.Functions/Functions/Metrics/GetGeographicMetricsFunction.cs
+++ b/src/Backend/AutopilotMonitor.Functions/Functions/Metrics/GetGeographicMetricsFunction.cs
@@ -117,14 +117,22 @@ namespace AutopilotMonitor.Functions.Functions.Metrics
var totalDownloadSecs = locationApps.Sum(a => (double)a.DownloadDurationSeconds);
var avgThroughput = totalDownloadSecs > 0 ? totalBytes / totalDownloadSecs : 0;
- // Delivery Optimization metrics (apps with DO telemetry have DoDownloadMode >= 0)
- var doApps = locationApps.Where(a => a.DoDownloadMode >= 0).ToList();
+ // Delivery Optimization metrics — use ALL apps with DO telemetry, not just those
+ // with DownloadDurationSeconds > 0 (small/fast apps have valid DO data but < 1s duration)
+ var allLocationApps = group
+ .Where(s => appsBySession.ContainsKey(s.SessionId))
+ .SelectMany(s => appsBySession[s.SessionId])
+ .ToList();
+ var doApps = allLocationApps.Where(a => a.DoDownloadMode >= 0).ToList();
var doSessionCount = group
.Where(s => appsBySession.ContainsKey(s.SessionId))
.Count(s => appsBySession[s.SessionId].Any(a => a.DoDownloadMode >= 0));
var totalDoPeers = doApps.Sum(a => a.DoBytesFromPeers);
var totalDoHttp = doApps.Sum(a => a.DoBytesFromHttp);
- var totalDoBytes = totalDoPeers + totalDoHttp;
+ // Use DoTotalBytesDownloaded as ground truth denominator (accounts for all sources);
+ // fall back to peers+http sum for old records without the field
+ var totalDoDownloaded = doApps.Sum(a => a.DoTotalBytesDownloaded);
+ var totalDoBytes = totalDoDownloaded > 0 ? totalDoDownloaded : (totalDoPeers + totalDoHttp);
var avgDoPct = totalDoBytes > 0 ? (double)totalDoPeers / totalDoBytes * 100 : 0;
locations.Add(new LocationMetrics
diff --git a/src/Backend/AutopilotMonitor.Functions/Services/TableStorageService.Metrics.cs b/src/Backend/AutopilotMonitor.Functions/Services/TableStorageService.Metrics.cs
index df34719c..27d3fd56 100644
--- a/src/Backend/AutopilotMonitor.Functions/Services/TableStorageService.Metrics.cs
+++ b/src/Backend/AutopilotMonitor.Functions/Services/TableStorageService.Metrics.cs
@@ -192,6 +192,8 @@ namespace AutopilotMonitor.Functions.Services
var existingDoPeers = existing.GetInt64("DoBytesFromPeers");
if (existingDoPeers.HasValue && existingDoPeers.Value > 0)
{
+ summary.DoFileSize = existing.GetInt64("DoFileSize") ?? 0;
+ summary.DoTotalBytesDownloaded = existing.GetInt64("DoTotalBytesDownloaded") ?? 0;
summary.DoBytesFromPeers = existingDoPeers.Value;
summary.DoBytesFromHttp = existing.GetInt64("DoBytesFromHttp") ?? 0;
summary.DoPercentPeerCaching = existing.GetInt32("DoPercentPeerCaching") ?? 0;
@@ -218,6 +220,8 @@ namespace AutopilotMonitor.Functions.Services
["StartedAt"] = EnsureUtc(summary.StartedAt),
["CompletedAt"] = summary.CompletedAt.HasValue ? EnsureUtc(summary.CompletedAt.Value) : (DateTime?)null,
// Delivery Optimization telemetry
+ ["DoFileSize"] = summary.DoFileSize,
+ ["DoTotalBytesDownloaded"] = summary.DoTotalBytesDownloaded,
["DoBytesFromPeers"] = summary.DoBytesFromPeers,
["DoBytesFromHttp"] = summary.DoBytesFromHttp,
["DoPercentPeerCaching"] = summary.DoPercentPeerCaching,
@@ -306,6 +310,8 @@ namespace AutopilotMonitor.Functions.Services
StartedAt = entity.GetDateTimeOffset("StartedAt")?.UtcDateTime ?? DateTime.MinValue,
CompletedAt = entity.GetDateTimeOffset("CompletedAt")?.UtcDateTime,
// Delivery Optimization telemetry
+ DoFileSize = entity.GetInt64("DoFileSize") ?? 0,
+ DoTotalBytesDownloaded = entity.GetInt64("DoTotalBytesDownloaded") ?? 0,
DoBytesFromPeers = entity.GetInt64("DoBytesFromPeers") ?? 0,
DoBytesFromHttp = entity.GetInt64("DoBytesFromHttp") ?? 0,
DoPercentPeerCaching = entity.GetInt32("DoPercentPeerCaching") ?? 0,
diff --git a/src/Shared/AutopilotMonitor.Shared/Models/Metrics/AppInstallSummary.cs b/src/Shared/AutopilotMonitor.Shared/Models/Metrics/AppInstallSummary.cs
index 94c3eae8..22d598c9 100644
--- a/src/Shared/AutopilotMonitor.Shared/Models/Metrics/AppInstallSummary.cs
+++ b/src/Shared/AutopilotMonitor.Shared/Models/Metrics/AppInstallSummary.cs
@@ -37,6 +37,12 @@ namespace AutopilotMonitor.Shared.Models
public DateTime? CompletedAt { get; set; }
// Delivery Optimization telemetry
+ /// DO: total file size reported by DO
+ public long DoFileSize { get; set; }
+
+ /// DO: total bytes actually downloaded (may differ from DoFileSize on partial downloads)
+ public long DoTotalBytesDownloaded { get; set; }
+
/// DO: bytes from all peer sources
public long DoBytesFromPeers { get; set; }