diff --git a/src/Backend/AutopilotMonitor.Functions.Tests/EventDataNormalizationTests.cs b/src/Backend/AutopilotMonitor.Functions.Tests/EventDataNormalizationTests.cs
new file mode 100644
index 00000000..dbef76f9
--- /dev/null
+++ b/src/Backend/AutopilotMonitor.Functions.Tests/EventDataNormalizationTests.cs
@@ -0,0 +1,118 @@
+using System.Collections.Generic;
+using AutopilotMonitor.Functions.Functions.Ingest;
+using AutopilotMonitor.Functions.Services;
+using AutopilotMonitor.Shared.Models;
+using Newtonsoft.Json;
+using Stj = System.Text.Json.JsonSerializer;
+
+namespace AutopilotMonitor.Functions.Tests;
+
+///
+/// Regression tests for the V2 ingest data-corruption bug: the telemetry payload parser used to
+/// skip the Newtonsoft-JToken → native normalization the V1 NDJSON path applied, so nested
+/// arrays/objects (e.g. hardware_spec.disks) reached System.Text.Json downstream as JObject/JArray
+/// and serialized to corrupt nested-empty-array output. Also covers DetectHasSSD, which used an
+/// exact mediaType compare that never matched the agent's composite values ("NVMe SSD").
+///
+public class EventDataNormalizationTests
+{
+ private const string TenantId = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";
+ private const string SessionId = "b2c3d4e5-f6a7-8901-bcde-f12345678901";
+
+ private static TelemetryItemDto EventDto(string payloadJson)
+ => new TelemetryItemDto
+ {
+ Kind = "Event",
+ PartitionKey = $"{TenantId}_{SessionId}",
+ RowKey = "0000000001",
+ TelemetryItemId = 1,
+ PayloadJson = payloadJson,
+ EnqueuedAtUtc = new System.DateTime(2026, 4, 21, 10, 0, 0, System.DateTimeKind.Utc),
+ };
+
+ // hardware_spec shape the agent actually emits — a nested object array (disks) and a nested
+ // object array (gpus), plus flat scalars.
+ private const string HardwareSpecPayload =
+ "{\"EventType\":\"hardware_spec\",\"Data\":{" +
+ "\"systemModel\":\"HP EliteBook 840 G8\"," +
+ "\"ramTotalGB\":7.7," +
+ "\"disks\":[{\"model\":\"KIOXIA\",\"sizeGB\":238,\"mediaType\":\"NVMe SSD\",\"busType\":\"NVMe\"}]," +
+ "\"gpus\":[{\"name\":\"Intel Iris Xe\",\"adapterRAMGB\":2}]" +
+ "}}";
+
+ [Fact]
+ public void ParseEvent_normalizes_nested_objects_to_native_types()
+ {
+ var evt = TelemetryPayloadParser.ParseEvent(EventDto(HardwareSpecPayload), TenantId, SessionId);
+
+ Assert.NotNull(evt);
+ // Nested array must be a native List