fix(siteruntime): harden WaitAsync — no spurious match on quality republish, guard throwing predicate, Ask-timeout returns false

This commit is contained in:
Joseph Doherty
2026-06-17 08:44:03 -04:00
parent 75ffa09b8f
commit 04e97f4a87
5 changed files with 390 additions and 32 deletions
@@ -39,19 +39,27 @@ public record WaitForAttributeRequest(
/// <summary>
/// Reply to a <see cref="WaitForAttributeRequest"/>. Exactly one of
/// <see cref="Matched"/> / <see cref="TimedOut"/> is set on the happy paths;
/// <see cref="ErrorMessage"/> is populated only on the defensive cap-exceeded path.
/// <see cref="ErrorMessage"/> is populated on the failure paths (per-instance
/// waiter cap exceeded, or the match predicate threw).
/// </summary>
/// <param name="CorrelationId">Echoes the request's correlation id.</param>
/// <param name="Matched">True when the attribute reached the target/predicate within the timeout.</param>
/// <param name="Value">The matched value (null on timeout / error).</param>
/// <param name="Quality">The attribute quality at match time (empty on timeout / error).</param>
/// <param name="Quality">
/// The attribute quality at match time; <see langword="null"/> on the non-match
/// paths (timeout / error / cap-exceeded), matching the nullable
/// <see cref="ErrorMessage"/> convention.
/// </param>
/// <param name="TimedOut">True when the timeout fired before a match.</param>
/// <param name="ErrorMessage">Non-null only when the wait was refused (e.g. per-instance waiter cap exceeded).</param>
/// <param name="ErrorMessage">
/// Non-null only when the wait failed/refused — the per-instance waiter cap was
/// exceeded, or the match predicate threw (<c>"Wait predicate threw: …"</c>).
/// </param>
public record WaitForAttributeResponse(
string CorrelationId,
bool Matched,
object? Value,
string Quality,
string? Quality,
bool TimedOut,
string? ErrorMessage = null);