Alarm historian: emit stable nonzero delivery IDs without changing queue dedup #705

Closed
opened 2026-10-13 06:39:53 -04:00 by dohertj2 · 1 comment
Owner

Proven sender identity finding from Gateway #28 investigation. Direct bounded SQL projections of OtOpcUaLiveValidation source2026-10-10..14 returned9 rows: six IDs are stored as Guid.Empty; three are nonzero GUIDs. Source AlarmEventMapper deliberately leaves proto HistorianEvent.Id unset, claiming the server assigns identity. Gateway instead maps empty to Guid.Empty and EventWriteProtocol serializes it unchanged. Valid nonzero GUIDs are supported; an arbitrary non-GUID alarm/condition ID must not be sent as event ID.

Existing AlarmSfSchema.DeriveId hashes serialized payload to a stable persisted64-hex queue key. This supports pair convergence/duplicate enqueue semantics and remains available in QueueRow.Id across retry/restart/replication. Drain currently discards that key when handing events to IHistorianEventWriter.

Acceptance: emit a nonzero valid event GUID, stable for durable redelivery/restart/failover, while preserving existing serialized payload fingerprint/dedup behavior and stable AlarmId condition identity. Distinct events sharing a timestamp must retain distinct delivery IDs; identical replicated payloads must converge as they do today. Cover queued/direct/legacy/migration routes, successful and faulted retry, mapper wire GUID and unchanged queue IDs/payload. Do not generate a new GUID per RPC or fabricate IDs during historical reads. Historical all-zero rows are not rewritten by this fix.

Gateway #39 tracks an independent timestamp-offset projection failure; that blocker is not an identity fix. No identity code changes or event writes made during investigation.

Proven sender identity finding from Gateway #28 investigation. Direct bounded SQL projections of OtOpcUaLiveValidation source2026-10-10..14 returned9 rows: six IDs are stored as Guid.Empty; three are nonzero GUIDs. Source AlarmEventMapper deliberately leaves proto HistorianEvent.Id unset, claiming the server assigns identity. Gateway instead maps empty to Guid.Empty and EventWriteProtocol serializes it unchanged. Valid nonzero GUIDs are supported; an arbitrary non-GUID alarm/condition ID must not be sent as event ID. Existing AlarmSfSchema.DeriveId hashes serialized payload to a stable persisted64-hex queue key. This supports pair convergence/duplicate enqueue semantics and remains available in QueueRow.Id across retry/restart/replication. Drain currently discards that key when handing events to IHistorianEventWriter. Acceptance: emit a nonzero valid event GUID, stable for durable redelivery/restart/failover, while preserving existing serialized payload fingerprint/dedup behavior and stable AlarmId condition identity. Distinct events sharing a timestamp must retain distinct delivery IDs; identical replicated payloads must converge as they do today. Cover queued/direct/legacy/migration routes, successful and faulted retry, mapper wire GUID and unchanged queue IDs/payload. Do not generate a new GUID per RPC or fabricate IDs during historical reads. Historical all-zero rows are not rewritten by this fix. Gateway #39 tracks an independent timestamp-offset projection failure; that blocker is not an identity fix. No identity code changes or event writes made during investigation.
Author
Owner

Resolved in PR #706 (master 7b238750; fix 10916362). Direct events retain one nonzero transport GUID across retries/copies. Queued events derive the GUID only from the persisted row key, including retry, restart, payload edits, replication, legacy migration and dead-letter revival. Queue JSON/key/schema/deduplication, business-field equality/hash, and AlarmId are preserved. The mapper emits the exact GUID and rejects an explicitly empty identity.

Verification: both original empty-wire-ID and changing-retry-ID regressions reproduced before fixes. Core 51/51, migration/convergence 16/16, Gateway 453 passed / 6 live skipped. Full offline solution: 14,635 passed, 611 skipped, zero failures across 62 suites, exit 0. Independent review and diff check clear; fetched merged tree equals the verified branch.

No live event writes, deployment or historical-row rewrite. Actual exact-ID persistence/readback remains tracked by Gateway #28, with its separate #39 provider/timestamp fault. Results: docs/plans/2026-10-13-alarm-delivery-identity-results.md.

Resolved in PR #706 (master 7b238750; fix 10916362). Direct events retain one nonzero transport GUID across retries/copies. Queued events derive the GUID only from the persisted row key, including retry, restart, payload edits, replication, legacy migration and dead-letter revival. Queue JSON/key/schema/deduplication, business-field equality/hash, and AlarmId are preserved. The mapper emits the exact GUID and rejects an explicitly empty identity. Verification: both original empty-wire-ID and changing-retry-ID regressions reproduced before fixes. Core 51/51, migration/convergence 16/16, Gateway 453 passed / 6 live skipped. Full offline solution: 14,635 passed, 611 skipped, zero failures across 62 suites, exit 0. Independent review and diff check clear; fetched merged tree equals the verified branch. No live event writes, deployment or historical-row rewrite. Actual exact-ID persistence/readback remains tracked by Gateway #28, with its separate #39 provider/timestamp fault. Results: docs/plans/2026-10-13-alarm-delivery-identity-results.md.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#705