967e5140f1
Executes a poll pass: resolve refs -> SqlGroupPlanner.Plan -> one command per group -> slice the result set back to per-tag DataValueSnapshots, positionally aligned with the caller's reference list (design §3.2). The frozen-peer contract (design §8.3, the R2-01 S7 lesson) is the core of it. CommandTimeout is only the server-side backstop; the client-side bound is a linked CancelAfter PLUS Task.WaitAsync, because a linked token bounds only a provider that honours it and ADO.NET providers vary. The whole per-group operation — waiting for a concurrency slot, OpenAsync, and the query — runs off one operationTimeout budget, so ReadAsync returns on time regardless of what the database is doing. A breach Bad-codes that group (BadTimeout); caller cancellation propagates instead, since nobody consumes a torn-down poll. Also: absent row (BadNoData) stays distinct from a NULL cell (Uncertain, or Bad under nullIsBad); duplicate plan members are all fed (two tags on one keyValue bind one parameter but stay two members); the concurrency slot is released by the work, not the waiter, so a frozen database can never hold more than maxConcurrentGroups connections; the whole call throws only when the connection itself cannot open, which is what earns PollGroupEngine's backoff. SqlStatusCodes is driver-local, matching every sibling driver's own table — there is no shared helper in Core.Abstractions and drivers do not reference the OPC UA SDK. Values were read off Opc.Ua.StatusCodes rather than copied from a sibling, because two of those tables carry transcription errors. Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW