feat(lmxproxy): add DatetimeArray proto type for DateTime[] round-trip fidelity

Added DatetimeArray message (repeated int64, UTC ticks) to proto and
code-first contracts. Host serializes DateTime[] → DatetimeArray.
Client deserializes DatetimeArray → DateTime[] (not raw long[]).
Client ExtractArrayValue now unpacks all array types including DateTime.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-03-22 15:08:15 -04:00
parent b050371dd5
commit ce3942990e
4 changed files with 56 additions and 15 deletions
@@ -120,6 +120,9 @@ public class ArrayValue
[DataMember(Order = 6)]
public StringArray? StringValues { get; set; }
[DataMember(Order = 7)]
public DatetimeArray? DatetimeValues { get; set; }
}
[DataContract]
@@ -164,6 +167,13 @@ public class StringArray
public List<string> Values { get; set; } = [];
}
[DataContract]
public class DatetimeArray
{
[DataMember(Order = 1)]
public List<long> Values { get; set; } = [];
}
// ────────────────────────────────────────────────────────────────
// Quality Code (v2)
// ────────────────────────────────────────────────────────────────
@@ -271,12 +271,30 @@ public partial class LmxProxyClient : ILmxProxyClient
TypedValueCase.StringValue => tv.StringValue,
TypedValueCase.BytesValue => tv.BytesValue,
TypedValueCase.DatetimeValue => new DateTime(tv.DatetimeValue, DateTimeKind.Utc),
TypedValueCase.ArrayValue => tv.ArrayValue,
TypedValueCase.ArrayValue => ExtractArrayValue(tv.ArrayValue),
TypedValueCase.None => null,
_ => null
};
}
internal static object? ExtractArrayValue(ArrayValue? av)
{
if (av is null) return null;
if (av.BoolValues is not null) return av.BoolValues.Values.ToArray();
if (av.Int32Values is not null) return av.Int32Values.Values.ToArray();
if (av.Int64Values is not null) return av.Int64Values.Values.ToArray();
if (av.FloatValues is not null) return av.FloatValues.Values.ToArray();
if (av.DoubleValues is not null) return av.DoubleValues.Values.ToArray();
if (av.StringValues is not null) return av.StringValues.Values.ToArray();
if (av.DatetimeValues is not null)
{
return av.DatetimeValues.Values
.Select(ticks => new DateTime(ticks, DateTimeKind.Utc))
.ToArray();
}
return null;
}
private async Task<T> ExecuteWithRetry<T>(Func<Task<T>> operation, CancellationToken ct)
{
if (_resiliencePipeline is not null)