Equipment mode now gates tag writes — migration guide¶
Issue #1255
makes ISA-88 equipment mode a real barrier on the gateway API. A direct tag
write to a ControlModule in Automatic mode is now refused with 403 Forbidden.
Before this change the barrier existed only in the HMI client, which decided
whether to render the write widgets, while the API accepted the write.
This is a behaviour change on an existing endpoint, and writes that succeed today will start failing. Read this before upgrading if anything other than the HMI writes tags.
Who is affected¶
Anything that writes a ControlModule tag through the gateway without first putting the module in Manual mode:
dcs tag set, which posts to the same route.- Integrations calling
POST /api/v1/sites/{site}/controlmodules/{cm}/tags/{tag}. - Integrations calling
POST /api/v1/sites/{site}/units/{unit}/tags/{address}with a ControlModule-qualified address such asmedia-steam-valve.CMD. - Test rigs, capture automation, and seeding scripts that poke tags directly.
The exposure is wider than it looks. ControlModuleSpec.Mode defaults to
Automatic, so a module is in Automatic unless something explicitly put it in
Manual. A deployment that never used the mode feature at all is fully affected.
Who is not affected¶
- Control algorithms. The SFC engine and the function-block scan write
in-process through
adapter.WriteTagand never traverse the gateway. A phase driving a tag is what Automatic mode means, and it continues unchanged. - Reads. Only writes are gated.
- Unit-level runtime variables. An address on the unit route whose prefix names no ControlModule has no equipment entity, so it has no equipment mode to consult and is left alone.
- HMI operators. The HMI already required Manual mode before it would render a write control, so the surface behaves as it always did.
What changed¶
| Route | Before | After |
|---|---|---|
POST …/controlmodules/{cm}/tags/{tag} |
Wrote regardless of mode | 403 while the module resolves to Automatic |
POST …/units/{unit}/tags/{address} with a CM-qualified address |
Wrote regardless of mode | 403 while that module resolves to Automatic |
Mode resolves status-over-spec, the same way every other surface resolves it, and an unset mode reads as Automatic.
The refusal is recorded in the audit trail as an Update with result
Rejected and reason AutomaticMode, so a write that did not happen is as
accountable as one that did.
How to migrate¶
Put the module in Manual before writing, and hand it back afterwards. This is
the ceremony docs/equipment-operation.md already documented.
dcs mode ControlModule media-steam-valve Manual -s plant-01
dcs tag set media-steam-valve.CMD=45 -s plant-01
dcs mode ControlModule media-steam-valve Automatic -s plant-01
curl -X POST "$GW/api/v1/sites/plant-01/mode" \
-H 'Content-Type: application/json' -H "X-DCS-Nonce: $(uuidgen)" \
-d '{"kind":"ControlModule","name":"media-steam-valve","mode":"Manual"}'
curl -X POST "$GW/api/v1/sites/plant-01/controlmodules/media-steam-valve/tags/CMD" \
-H 'Content-Type: application/json' -H "X-DCS-Nonce: $(uuidgen)" \
-d '{"value":45}'
curl -X POST "$GW/api/v1/sites/plant-01/mode" \
-H 'Content-Type: application/json' -H "X-DCS-Nonce: $(uuidgen)" \
-d '{"kind":"ControlModule","name":"media-steam-valve","mode":"Automatic"}'
Returning the module to Automatic leaves the written value standing. Automatic mode means the control algorithm owns the module from that point on, so whatever the algorithm drives will move the value on its next scan. A tag no algorithm writes keeps what the operator set.
A module left in Manual stays writable, which is a decision to make deliberately: it is the state in which the control algorithm does not own the equipment.
Why this remedy¶
ISA-88 Part 1 Clause 3.1.35 defines mode as "the accessibility for manipulating the states of equipment entities", and Table 1's Automatic (Basic Control) row states the consequence directly: "The equipment cannot be manipulated directly by the operator."
The standard offers those modes as examples and requires none of them. This product adopted the names, documents them against Table 1, and ships a faceplate whose Automatic state is presented to operators as locking the write controls. Keeping the API permissive would have meant documenting that our ISA-88 mode is a rendering hint, on a page in the compliance section. Making the barrier real was the smaller cost.