Merge R2-11 TagConfig consolidation (arch-review round 2) [PR #434]
Findings 01/C-1, 01/P-1 (single TagConfigIntent.Parse in Commons, 4 copies delegate, parse-once) + 05 CONV-2/UNDER-1/UNDER-6 (shared strict TagConfigJson readers, per-driver Inspect() + writable key, FOCAS capability pre-flight, Modbus probe timeoutMs, deploy-gate Warn|Error). Phase C runtime-strict flip deferred. T22/T24 deferred. Auto-merged AddressSpaceApplier.cs + DriverHostActor.cs with R2-04/R2-10; verified OpcUaServer.Tests 286/286 + Runtime.Tests 396/396. Build clean.
This commit is contained in:
+47
@@ -231,6 +231,53 @@ Combined with historization (values are arrays — history of the whole array sn
|
||||
|
||||
See the individual driver docs under `docs/drivers/` for per-driver implementation details.
|
||||
|
||||
## Writable equipment tags (`writable` key)
|
||||
|
||||
An equipment tag is **writable by default** — the materialised OPC UA node is created
|
||||
`CurrentReadWrite` and inbound client writes are routed to the device (subject to the
|
||||
`WriteOperate` LDAP role gate). Setting the optional `"writable": false` key in a tag's
|
||||
`TagConfig` makes the node **read-only** at the driver seam. The six typed tag editors
|
||||
(Modbus, S7, AB CIP, AB Legacy, TwinCAT, FOCAS) expose this as a **Writable** checkbox
|
||||
(checked by default); it can also be hand-authored in the raw-JSON textarea.
|
||||
|
||||
| Condition | Node |
|
||||
|---|---|
|
||||
| `writable` absent | Writable (driver default) — existing configs are unchanged |
|
||||
| `writable: false` | Read-only |
|
||||
| `writable: true` | Writable |
|
||||
|
||||
The key is honoured by Modbus, S7, AB CIP, AB Legacy, and TwinCAT. **FOCAS forces
|
||||
read-only regardless** — FOCAS PMC writes are unsupported in the wire client, so its
|
||||
editor shows the checkbox disabled/unchecked and any authored `writable:true` is ignored
|
||||
(and flagged at the deploy gate below). Node-level authz (LDAP `WriteOperate`) remains the
|
||||
effective write gate above this flag.
|
||||
|
||||
## Deploy-time TagConfig validation (`Deployment:TagConfigValidationMode`)
|
||||
|
||||
The deploy gate inspects every equipment tag's `TagConfig` per its bound driver type and
|
||||
surfaces **strictness warnings** — a present-but-invalid enum value (e.g. a typo'd
|
||||
`dataType`, which the lenient runtime silently defaults to the wrong width with `Good`
|
||||
status), a structurally-unparseable TagConfig, or (FOCAS) an authored `writable:true`.
|
||||
|
||||
The behaviour is controlled by `Deployment:TagConfigValidationMode` in `appsettings.json`:
|
||||
|
||||
| Mode | Behaviour |
|
||||
|---|---|
|
||||
| `Warn` (default) | Non-blocking: warnings are logged and appended to the deployment result message; the deploy still succeeds. Existing configs never break. |
|
||||
| `Error` | Blocking: warnings fold into the draft-gate reject list — a config with a typo'd enum (or unparseable TagConfig) cannot be re-deployed until fixed. Opt-in per environment once the fleet deploys warning-clean. |
|
||||
|
||||
Running servers are untouched either way — the gate only sees re-deploys. Unmapped drivers
|
||||
(Galaxy, OpcUaClient) are skipped. **Unknown keys are never warned on**: the `TagConfig`
|
||||
blob is a shared namespace (platform intent keys coexist with per-driver address keys and
|
||||
forward-compat keys the typed editors preserve), so there is no single schema to validate
|
||||
against — parsers read known fields and ignore the rest by design.
|
||||
|
||||
> **Note (runtime strictness is deferred).** In this release the runtime parsers stay
|
||||
> *lenient* (a typo'd enum still silently defaults) — only the deploy gate reports it.
|
||||
> Flipping the runtime parsers to strict (a typo'd enum ⇒ `BadNodeIdUnknown` instead of a
|
||||
> wrong-width `Good`) is a deliberate future phase, to be taken only after fleets have run
|
||||
> `Error` mode clean. Tracked in `archreview/plans/STATUS.md`.
|
||||
|
||||
## Galaxy address picker — native-alarm pre-fill
|
||||
|
||||
When the Galaxy address picker selects an attribute that is itself an alarm
|
||||
|
||||
@@ -15,6 +15,16 @@ OtOpcUa is **read-only** against FOCAS; all reads go over the native wire
|
||||
protocol using the documented command IDs. Writes return
|
||||
`BadNotWritable` by design.
|
||||
|
||||
> **Equipment tags are forced read-only (R2-11, migration note).** The equipment-tag parser
|
||||
> (`FocasEquipmentTagParser`) now hard-codes `Writable: false` regardless of any authored
|
||||
> `"writable": true` — previously such a tag advertised a writable node whose write always failed at
|
||||
> the wire with `BadNotWritable`; now it fails one step earlier at the driver seam (same family of Bad
|
||||
> status, no successful operation changes). The AdminUI FOCAS editor shows the Writable checkbox
|
||||
> disabled/unchecked, and the deploy gate warns when a config requests `writable:true`. Additionally,
|
||||
> equipment-tag references now run the same capability-matrix pre-flight authored tags get: a reference
|
||||
> whose address violates the device series' matrix fails to resolve (`BadNodeIdUnknown`) instead of
|
||||
> reaching the wire. Honour `writable` here once PMC writes ship in the wire client.
|
||||
|
||||
> **PDU version (v3 / FANUC 30i/31i).** The wire client **accepts inbound PDU versions `{1, 3}`**
|
||||
> (`FocasWireProtocol`) while still emitting v1 on requests. Older controls + the docker mock answer
|
||||
> v1; modern controls (Makino Pro 5 / FANUC **31i-B**) answer v3. **Validated live against a real
|
||||
|
||||
Reference in New Issue
Block a user