feat(historian): serve DurationGood/DurationBad on the SQL backends; pin the #821 late-start facts (#820, #821)
#820: SqlServer + QuestDB now serve Part 13 DurationGood / DurationBad from the same Good / Bad region totals TimeWeightedAggregator already computes for PercentGood / PercentBad — reported in milliseconds (OPC UA Duration, the SDK's unit), Uncertain time in neither (Mantis 0006166), same BadNoData / status / Partial rules. AggregateFamilies.Served grows 17 -> 19, so i=11201 and the up-front refusal follow automatically; Gateway still refuses both (explicit served set, unchanged). Client.Shared AggregateType / mapper / CLI gain both. The #796 oracle answers DurationGood through the Good-only subclass as well. QualityMix conformance asserts both directly (Q and QP, hand values, ms, and = PercentGood x interval), replaces the "refused up front" test, and adds Duration* to the forward/reverse/truncated oracle comparisons. #821 (facts only, no decision): SdkAggregateParityTests pins an Uncertain-first late-start interval (QP over [0,20), both directions) against ours (Part 13 Total 163.96, TimeAverage 10.93), the frozen 1.5.378.182 calculators (188.96, 9.448), SDK 2.0.1's stock calculators (188.96, 9.448) and a Good-first control (all 163.96); LiveAggregateLateStartFactsTests pins the same through the booted server's runtime AggregateManager (live AggregateFilter) incl. DurationGood 15000 / PercentGood 75 there vs 8000 / 40 in HistoryRead (#809). QualityMix adds the reverse late-start variant (reverse TW pin + reverse oracle windows). Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+3
-3
@@ -359,7 +359,7 @@ public sealed class SqlServerHistorianDataSource : IHistorianDataSource
|
||||
/// <inheritdoc />
|
||||
public bool SupportsReverseEvents => true;
|
||||
|
||||
// <remarks>The seventeen <see cref="AggregateFamilies.Served"/> — shared with the other SQL backend.</remarks>
|
||||
// <remarks>The nineteen <see cref="AggregateFamilies.Served"/> — shared with the other SQL backend.</remarks>
|
||||
/// <inheritdoc />
|
||||
public IReadOnlySet<HistoryAggregateType> SupportedAggregates => AggregateFamilies.Served;
|
||||
|
||||
@@ -463,7 +463,7 @@ public sealed class SqlServerHistorianDataSource : IHistorianDataSource
|
||||
// bucket start (its later edge on a reverse read), except Minimum/MaximumActualTime (the sample's time; ties ⇒
|
||||
// earliest) and Start/End. Every aggregate but Average sets the Partial bit on the bucket the tag's earliest
|
||||
// sample lies strictly inside (forward) or its latest sample lies in (reverse: strictly inside).
|
||||
// PercentGood / PercentBad are duration-based (time-weighted family, below). Count counts Good samples (value-based status; 0/Good on an empty bucket inside the tag's
|
||||
// DurationGood / DurationBad / PercentGood / PercentBad are duration-based (time-weighted family, below). Count counts Good samples (value-based status; 0/Good on an empty bucket inside the tag's
|
||||
// data range), Start/End are the raw first/last sample of any quality, Delta is Uncertain only when the bucket's
|
||||
// first or last sample is not usable (see <see cref="AggregateEvaluator"/>).
|
||||
// </para>
|
||||
@@ -475,7 +475,7 @@ public sealed class SqlServerHistorianDataSource : IHistorianDataSource
|
||||
// <see cref="TimeWeightedAggregator"/>, which fills every interval (an empty one between bounds gets a value).
|
||||
// </para>
|
||||
// </remarks>
|
||||
// <exception cref="HistoryAggregateNotSupportedException">The aggregate is not one of the seventeen served.</exception>
|
||||
// <exception cref="HistoryAggregateNotSupportedException">The aggregate is not one of the nineteen served.</exception>
|
||||
// <exception cref="ArgumentOutOfRangeException">The window holds more than <see cref="MaxProcessedBuckets"/> intervals.</exception>
|
||||
/// <inheritdoc />
|
||||
public async Task<HistoryReadResult> ReadProcessedAsync(
|
||||
|
||||
Reference in New Issue
Block a user