Correct the signals framing in the README

signals.yml is managed by the sidecar, not authored by the customer, and
the write flag is used by the supporting services rather than being a
script author's lever. The previous text presented both as a customer
contract, which is wrong.

Now claims only runtime behaviour: which signals a job sees is configured
for it, an unexposed signal is absent rather than an error, and batch
rejection is described as the sidecar not recognising an id. Also points a
customer at their own job output rather than platform-side logs they may
not have access to.
This commit is contained in:
Iñigo Etxaniz
2026-08-04 09:45:44 +02:00
parent 16b9a265d1
commit dc3a0f8b0b
+12 -17
View File
@@ -43,18 +43,12 @@ other submodule paths work equally well.
## Signals
A signal is reachable from a script only if it is listed in the job's `signals.yml`, with
`read: 1` to appear in `plant.state` and `write: 1` to accept a write. Ids and names both
come from that file and must match the ids configured in i7state.
Not every signal is available to every job. `plant.state` holds only the signals the job's
sidecar exposes to it, keyed by both id and name. Which those are is configured for the job;
a script does not declare them.
```yaml
- { id: 21, name: 'oven-temperature', read: 1, write: 0 }
- { id: 49, name: 'oven-output', read: 0, write: 1 }
```
A signal missing from `signals.yml`, or listed with `read: 0`, is simply absent from
`plant.state` — it does not raise. Guard with `in` or `.get()` rather than assuming a key
exists.
A signal that is not exposed is simply absent from `plant.state` — reading it does not raise.
Guard with `in` or `.get()` rather than assuming a key is there.
## i7lib.client
@@ -85,9 +79,9 @@ call `run` uses; it is what keeps a script in step with the sample clock instead
**`add(signal_id, value, name="")`** — queues one write. `signal_id` is coerced to `int`,
`value` to `float`, `name` to `str`.
A batch is **all or nothing**. If any id in it is not in the job's `signals.yml`, the sidecar
rejects the entire batch and none of the writes land. Ids that are known but not marked
`write: 1` are skipped without failing the batch. Neither outcome is visible to the caller —
A batch is **all or nothing**. If the sidecar does not recognise one of the ids in it, the
entire batch is rejected and none of the writes land. An id it does recognise but which is
not writable is skipped without failing the batch. Neither outcome is visible to the caller —
see Error handling below.
### `run(logic_func, interval_ms=1000, offset_ms=200)`
@@ -141,6 +135,7 @@ rows" alike; `send` returning normally does **not** mean the writes were applied
rejected in full for one unknown id looks exactly like a successful send from inside the
script.
So when a value is not moving, check the job's stdout for the printed error first, then the
sidecar and i7state logs, which record every write as applied, rejected or unknown. Do not
infer success from the absence of an exception.
So when a value is not moving, check the job's own output first — that is where this library
prints its errors. If nothing appears there, the write reached the platform and was rejected
or dropped further in, which is visible only in the platform-side logs. Do not infer success
from the absence of an exception.