Files
ScadaBridge/src/ZB.MOM.WW.ScadaBridge.Commons/Messages/Instance/WaitForAttribute.cs
T
Joseph Doherty 63c16d6912 refactor(comm): retire ClusterClient naming after the gRPC cutover
Phase 4 of the ClusterClient -> gRPC migration deleted the Akka transports
but left the naming behind: `ClusterClientSiteAuditClient` was transport-
agnostic and worked unchanged, so it survived the deletion under a name
that now describes a transport the repo no longer has. Same for a scatter
of doc-comments still framing gRPC as "the new transport" beside an Akka
one that is gone.

Renames it to `SiteCommunicationAuditClient` (and its test file) and
rewrites the stale comments to describe the single transport that exists.
Also tightens CLAUDE.md: drops the self-describing directory listing and
the 27-component enumeration in favour of the non-obvious parts only.

Behaviour-neutral: names and prose only. Recorded as the Phase 4
follow-up in docs/plans/2026-07-22-clusterclient-to-grpc-plan.md.
2026-07-27 15:40:01 -04:00

83 lines
4.2 KiB
C#

namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Instance;
/// <summary>
/// Request to wait, event-driven, until an attribute reaches a value (or any
/// value satisfying a predicate), bounded by a timeout — the backing protocol for
/// the script-facing <c>Attributes.WaitAsync</c> helper.
///
/// <para>
/// <b>Site-local only.</b> The optional <see cref="Predicate"/> is a non-serializable
/// in-process delegate, so this message MUST flow only within a single site node's
/// actor system (script execution → Instance Actor). It is never sent across the
/// site↔central gRPC boundary. The value-equality form (<see cref="TargetValueEncoded"/>)
/// would serialize, but the routed/inbound variant is deliberately out of scope here.
/// </para>
/// </summary>
/// <param name="CorrelationId">Per-wait correlation id; keys the waiter registry and the timeout self-message.</param>
/// <param name="InstanceName">The instance this wait targets.</param>
/// <param name="AttributeName">The attribute to watch — already scope-resolved by the accessor.</param>
/// <param name="TargetValueEncoded">
/// The codec-encoded target value (<c>AttributeValueCodec.Encode(target)</c>). A
/// match compares the codec-encoded form of the current value against this string.
/// When both this and <see cref="Predicate"/> are null the wait matches on ANY change.
/// </param>
/// <param name="Predicate">
/// Site-local predicate tested against the raw (decoded) current value. Mutually
/// exclusive with <see cref="TargetValueEncoded"/> — null when the encoded target is used.
/// </param>
/// <param name="Timeout">How long to wait before self-evicting with a timeout reply.</param>
/// <param name="OccurredAtUtc">When the request was issued (UTC).</param>
/// <param name="RequireGoodQuality">
/// Quality-gated ("Good"-only) mode (spec §4.2): when <see langword="true"/>, a
/// match additionally requires the attribute quality to be exactly
/// <c>"Good"</c> (<see cref="System.StringComparison.Ordinal"/>) — a value that
/// reaches the target / satisfies the predicate at Bad/Uncertain quality is NOT a
/// match and the waiter stays pending until the value satisfies the test at Good
/// quality (or times out). Defaults to <see langword="false"/> (quality-agnostic:
/// the match tests the value only). Trailing/defaulted so existing positional
/// constructions compile unchanged.
/// </param>
public record WaitForAttributeRequest(
string CorrelationId,
string InstanceName,
string AttributeName,
string? TargetValueEncoded,
Func<object?, bool>? Predicate,
TimeSpan Timeout,
DateTimeOffset OccurredAtUtc,
bool RequireGoodQuality = false);
/// <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 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; <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 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,
bool TimedOut,
string? ErrorMessage = null);
/// <summary>
/// Internal self-message scheduled by the Instance Actor to fire a waiter's
/// timeout. Site-local only; never crosses a cluster boundary.
/// </summary>
/// <param name="CorrelationId">The waiter whose timeout fired.</param>
public record WaitForAttributeTimeout(string CorrelationId);