docs(r2-06): 0.2.0 DataType provisioning delta (upsert/retype) + HISTGW_BOOL_SANDBOX_TAG recipe (06/U-7)

This commit is contained in:
Joseph Doherty
2026-07-13 10:02:37 -04:00
parent 1aa89d754f
commit e5cf986a10
3 changed files with 44 additions and 2 deletions
+6
View File
@@ -315,6 +315,11 @@ When the section is disabled the applier binds the no-op `NullHistorianProvision
run. Every dispatch logs a tally (`dispatched/requested/ensured/skipped/failed`); `dispatched=N` with
`requested=0` flags the dormant no-op. The API key must carry `historian:tags:write` for `EnsureTags`. (PR
#423 shipped `GatewayTagProvisioner` but left this wiring out, so provisioning was dormant; restored 2026-06-27.)
**0.2.0 DataType delta (archreview 06/U-7):** `EnsureTags` is an **upsert** (create-or-update, not
skip-if-exists), and the 0.2.0 `HistorianTagDefinition.DataType` proto3-optional change means Boolean tags now
provision as **Int1** (0.1.0 silently defaulted them to Float). A pre-bump Float Boolean is asked to retype
on its next deploy; the AVEVA-side retype policy is pinned by the live retype probe — see the "0.2.0 DataType
provisioning delta" section in `docs/Historian.md`.
### Gateway-side prerequisites
@@ -349,6 +354,7 @@ export HISTGW_GATEWAY_ENDPOINT=https://wonder-sql-vd03:5222 # absolute gateway
export HISTGW_GATEWAY_APIKEY=histgw_<id>_<secret> # must carry historian:read + historian:write (+ tags:write) scopes
export HISTGW_TEST_TAG=<existing-tag> # read round-trip
export HISTGW_WRITE_SANDBOX_TAG=<writable-float-tag> # e.g. HistGW.LiveTest.Sandbox — write round-trip (EnsureTags + write)
export HISTGW_BOOL_SANDBOX_TAG=<writable-bool-tag> # e.g. HistGW.LiveTest.BoolSandbox — 0.2.0 Boolean EnsureTags leg + retype probe (06/U-7)
export HISTGW_ALARM_SOURCE=<source-name> # alarm SendEvent → ReadEvents round-trip
dotnet test --filter "Category=LiveIntegration"
```
@@ -65,7 +65,7 @@
{
"id": "T9",
"subject": "U-7 docs: migration/assessment note (EnsureTags is upsert; pre-bump Float Booleans; three retype hypotheses; failed=N tally observability) in docs/Historian.md + CLAUDE.md HISTGW_BOOL_SANDBOX_TAG recipe update; commit 2 (U-7) after T7-T9",
"status": "pending",
"status": "completed",
"blockedBy": [
"T8"
]
+37 -1
View File
@@ -129,6 +129,35 @@ for this node), which is the signal to check that `ServerHistorian:Enabled=true`
> so a HistoryRead on it runs to the full `CallTimeout` (~30 s) before erroring. Auto-provisioning on deploy
> keeps freshly-historized tags from hitting that slow path. See the `CallTimeout` row above.
### 0.2.0 DataType provisioning delta (archreview 06/U-7)
`EnsureTags` is contract-documented (HistorianGateway 0.2.0) as an **upsert** — *"creates or updates
historian tags according to the given definitions"* — that maps per-tag onto AVEVA's
`HistorianClient.EnsureTagAsync(definition) -> bool`. It is **not idempotent** (not routed through the
idempotent retry pipeline) and **not skip-if-exists**.
The 0.1.0→0.2.0 client bump made `HistorianTagDefinition.DataType` **proto3-optional** (explicit presence).
Under 0.1.0, the provisioner's `Boolean → Int1` mapping sent wire value `0`, indistinguishable from unset, so
the gateway defaulted such tags to the SDK-default **Float**. Under 0.2.0 the same call carries explicit
presence, so Boolean tags now provision as **Int1** (the pre-existing intent of `HistorianTypeMapper` — no
mapper code change is needed or wanted). Consequences:
1. **New Boolean tags provision correctly as Int1.** This is the fix arriving as a silent, zero-diff
semantic change from the bump.
2. **Pre-bump Boolean tags exist historian-side as Float.** On the next deploy that dispatches provisioning
for such a tag, the gateway is asked (via the upsert) to update it to Int1. The AVEVA-side outcome of an
in-place analog retype is the one thing the contract does not pin; the candidate behaviors are
(i) **accepted with tag versioning** (history preserved under the old version, new writes under Int1),
(ii) **accepted as a plain retype**, or (iii) **rejected per-tag**`TagOperationResult.Success=false`
→ counted in the provisioner's `failed=N` dispatch tally. Only a live run distinguishes these — see the
**retype probe** (`EnsureTags_type_change_outcome_is_observable`) in the [Live /run gate](#live-run-gate).
*(This list is replaced with the observed answer after the first live run.)*
3. **The failure mode is bounded and observable either way.** Provisioning is fire-and-forget and never
blocks/fails a deploy; a per-tag rejection surfaces only as the tally's `failed` count. Values written to
a still-Float tag by the recorder remain readable (Float supersets Int1's 0/1 range); nothing is lost
pending a reconcile. A bulk retype sweep is **not** done in code — assess via the probe first, then decide
whether reconciliation is a one-time operator action.
---
## HistoryRead behavior
@@ -350,7 +379,14 @@ AVEVA Historian behind it healthy. Set `ServerHistorian:Enabled=true` with the c
least one historized Galaxy tag. The gate is operator-driven — it is not part of the local docker-dev rig.
The gateway-backed driver also ships an env-gated live suite (`Category=LiveIntegration`); see the
`HISTGW_GATEWAY_ENDPOINT` / `HISTGW_GATEWAY_APIKEY` / `HISTGW_TEST_TAG` / `HISTGW_WRITE_SANDBOX_TAG` /
`HISTGW_ALARM_SOURCE` env vars (it skips cleanly when they are absent).
`HISTGW_BOOL_SANDBOX_TAG` / `HISTGW_ALARM_SOURCE` env vars (it skips cleanly when they are absent).
`HISTGW_BOOL_SANDBOX_TAG` (e.g. `HistGW.LiveTest.BoolSandbox`, a **dedicated** writable Boolean tag —
never the shared Float write sandbox) drives the 0.2.0 Boolean `EnsureTags` leg
(`EnsureTags_boolean_sandbox_provisions_as_Int1`) and the retype probe
(`EnsureTags_type_change_outcome_is_observable`) that resolve the
[0.2.0 DataType provisioning delta](#020-datatype-provisioning-delta-archreview-06u-7) open question. Running
the full suite against a **0.2.0** gateway (all six tests, none skipped) also discharges 06/U-2's
"full documented run" for the historian suite.
See [AlarmHistorian.md](AlarmHistorian.md) for the alarm write path and
[ServiceHosting.md](ServiceHosting.md) for the (external) HistorianGateway deployment.