Skip to content

PQC209 — Initial state must use a snapshot, not events

A device event is published from OnConnected, while the adapter is reading initial state.

IConnectionAware.OnConnected runs after the link comes up, when the adapter reads what the panel currently looks like. That read answers what is true now. An event answers what just happened. They are different planes, and initial state belongs to the first one.

// reported
public async Task OnConnected(ConnectionContext context)
{
    foreach (var zone in _zones)
        if (zone.IsInAlarm)
            await zone.Alarm(DeviceTimestamp.UtcNow);   // this alarm did not just happen
}

Why the build refuses this

It writes history that never occurred. The zone went into alarm at some point the adapter never saw. Publishing it now asserts an occurrence at connect time — a false record, with the wrong timestamp, attributed to nothing.

Every dropped link repeats it. A flapping connection replays the whole panel into the audit log, once per reconnect. The audit trail fills with events nobody can act on, and the real ones are buried among them.

Status already carries this. The state plane exists exactly to answer "what does the panel look like right now", and the UI reads it. Nothing is lost by leaving initial state there.

How to fix it

Apply the state as a snapshot.

public async Task OnConnected(ConnectionContext context)
{
    var states = await _protocol.ReadAllZones(context.CancellationToken);
    await ApplySnapshotState(states);   // status plane - no audit records
}

If the device holds events that occurred while the adapter was disconnected, those come from the history path — a real event stream with real device timestamps — not from a state read.

What is not reported

Adapter-operational events. Connection loss and restore, synchronization lifecycle, command errors — the adapter's own truthful observations about its own behaviour. They are unmarked on purpose and may fire wherever they need to.

A method named OnConnected on a type that does not implement IConnectionAware. Not the connect path.

Publishing from a helper OnConnected calls. The check does not follow calls out of the method. The rule still applies.

If you disagree with a report

Do not suppress it. A wrong report is a bug in the check — report it with the code that triggered it.