fix(historian): #687 Gateway raw reads drop AVEVA's synthetic start-boundary row

An AVEVA Full raw read leads with a row stamped at the query start (the value in
effect, Quality=133, or a no-data NULL row); it was returned as a stored sample.
Raw reads now use the #681 classification (RawAggregateReader.RequestStartFor /
IsWindowSample — one authority, by timestamp, since a stored NULL looks the same
on the wire): request from 1 ms early with NumValuesPerNode + 16 rows, keep rows
at or after StartTime, drain the whole stream. A full page still holds exactly
the cap, so #669 paging/resume/tie-cluster reads are unchanged; a margin that
swallows the allowance fails the node rather than ending paging early.
ReturnBounds is not plumbed on any backend (documented).
This commit is contained in:
Joseph Doherty
2026-10-12 14:35:20 -04:00
parent 44a03bedc0
commit 9e47532283
6 changed files with 332 additions and 15 deletions
@@ -20,11 +20,13 @@ public sealed class GatewayHistorianDataSourceTests
},
};
var ds = new GatewayHistorianDataSource(fake, NullLogger<GatewayHistorianDataSource>.Instance);
var r = await ds.ReadRawAsync("T", DateTime.UtcNow.AddMinutes(-5), DateTime.UtcNow, 100, TestContext.Current.CancellationToken);
var start = new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var r = await ds.ReadRawAsync("T", start, start.AddMinutes(5), 100, TestContext.Current.CancellationToken);
Assert.Equal(2, r.Samples.Count);
Assert.Equal(0x80000000u, r.Samples[1].StatusCode); // Bad from quality 0
Assert.Equal("T", fake.LastReadRawTag);
Assert.Equal(100, fake.LastReadRawMaxValues);
// #687: asked from 1 ms before the window with room for AVEVA's boundary row (GatewayRawBoundaryRowTests).
Assert.Equal(100 + RawAggregateReader.PreWindowAllowance, fake.LastReadRawMaxValues);
}
[Fact]