#899 — EnsureTags is an upsert, so binding a node to an existing AVEVA tag via
historianTagname re-typed/re-described it on every add and host start.
- TagConfig `historianReadOnly: true` (TagConfigIntent -> RawTagPlan.HistorianReadOnly):
HistoryRead from an existing historian tag that OtOpcUa never provisions and never
records into (AddressSpaceApplier.IsOwnedHistorizedValue gates both the EnsureTags
hook and the recorder feed). Node-inert: surgical, not mirrored on UNS refs, in the
RawTagPlan equality/hash. A non-bool value is the deploy error HistorianReadOnlyInvalid.
AdminUI: CSV column HistorianReadOnly (strict), TagHistorizeConfig reads via the
runtime parse.
- ServerHistorian:ProvisionTags = CreateOrUpdate (default, unchanged) | CreateOnly
(Gateway only: TagExistsAsync first, existing tags left alone, failed lookup not
sent) | Off. Unknown value / CreateOnly on a SQL backend fail host start.
- Default for an explicit historianTagname stays OWNED: overrides pin owned history
across renames, a read-only default would silently stop provisioning + recording.
#898 — the hook parsed Tag.DataType (an OPC UA name) as DriverDataType, so historized
Float/Double/Byte/SByte tags were never provisioned. New shared
HistorianDataTypeNames.TryResolve: Float->Float32, Double->Float64, Byte/SByte->Int16
(lossless, provisioned as Int2); unmapped names logged at Information. Gateway now skips
Int64/UInt64 (HistorianGateway cannot create Int8/UInt8: lossless-cast-or-reject).
UPGRADE: the first host start after this provisions (upserts) every existing historized
Float/Double/Byte/SByte tag. Mark foreign-tag bindings historianReadOnly, or set
ServerHistorian:ProvisionTags=CreateOnly/Off, before upgrading (docs/Historian.md).
Claude-Session: https://claude.ai/code/session_01GT67ACmpMR7b9LGRPLijMi