Operator Actions: QA wait-for-ready

The OET supports operator actions: operator interventions made at runtime that control the behaviour of observing scripts. The first use case for this functionality is to give operators control over whether observing scripts wait for the system to be ‘QA Ready’ before proceeding with a scan. This behaviour is split into two mechanisms: a persistent global state that applies to every script run on that subarray, and a one-shot scan-level override that bypasses the wait for the current scan only.

Persistent state

The ScriptExecutionService holds a ScriptContext instance whose wait_for_qa_ready attribute is a simple boolean. When True (the default), the context signals to scripts that they should wait for QA readiness before each scan.

This flag is initialised from the OET_WAIT_FOR_QA_READY environment variable (see src/ska_oso_oet/config.py), defaulting to true if unset. It can be changed at runtime by an operator and persists across script executions for the lifetime of the OET instance — that is, until the pod restarts.

When a script is started, the current flag value is injected into the script’s keyword arguments as kwargs["context"]["wait_for_qa_ready"], so every script receives the up-to-date value at launch time.

Scan-level override

In addition to the persistent flag, an operator can send a one-shot override signal. This does not change the persistent state at all — it is a fire-and- forget event published on the operator.wait_for_qa_ready.override pypubsub topic. Scripts that want to honour it must subscribe to that topic and use the signal to release whatever blocking wait they hold in their scan loop.

The OET does not track whether a running script acted on an override. The semantics of “current scan” are defined entirely by the script.

Internal event flow

All operator actions are mediated by pypubsub topics defined in topics:

Topic

Purpose

topics.operator.wait_for_qa_ready.override

One-shot scan bypass.

topics.operator.wait_for_qa_ready.enable

Persistent enable.

topics.operator.wait_for_qa_ready.disable

Persistent disable.

topics.request.operator.override.state

Request topic used by GET /operator-actions.

topics.operator.override.state

Response topic carrying the current ScriptContext.

The sequence for a persistent state change is:

  1. FastAPIWorker receives the POST and publishes to the relevant topics.operator.wait_for_qa_ready.* topic.

  2. The ScriptExecutionService handler methods (handle_wait_for_qa_ready_enable, handle_wait_for_qa_ready_disable) sees these pubsub messages and mutate the value of ScriptContext.wait_for_qa_ready to match.

  3. The next script to start receives the updated value of wait_for_qa_ready via its context argument.

  4. Already-running scripts can also subscribe to the same topics to react to state changes mid-execution.

For a state query (GET), the ScriptExecutionServiceWorker uses a synchronous request–response pattern over pypubsub: it publishes to request.operator.override.state and returns the ScriptContext received on operator.override.state.

All operator actions are broadcast on the OET SSE stream, so external clients can observe override activity in real time without polling. This allows, for example, the OET UI to reflect the state set by the OST in another session.

REST API

Operator actions are served under the /operator-actions endpoint:

Method

Endpoint

Purpose

GET

/operator-actions

Returns the current ScriptContext. Only the persistent flag is reported; scan-level overrides are not tracked.

POST

/operator-actions

Publishes an operator action. Returns 202 Accepted immediately — the action propagates asynchronously through the event bus.

POST body

The POST body is {"topic": "<action>"} where <action> is one of:

Topic

Effect

operator.wait_for_qa_ready.enable

Set the persistent flag to True. Affects all subsequent scripts.

operator.wait_for_qa_ready.disable

Set the persistent flag to False. Affects all subsequent scripts.

operator.wait_for_qa_ready.override

One-shot signal to bypass the QA wait for the current scan. The persistent flag is unchanged.

Authentication

GET requires the ACTIVITY_READ scope; POST requires ACTIVITY_EXECUTE. Both require an authorised role (SW_ENGINEER, the telescope operator role, or APP2APP).

CLI

The oet wait_for_qa_ready subcommand wraps the REST API:

# always wait for QA before scanning (persists)
oet wait_for_qa_ready enable --subarray_id=1

# never wait for QA before scanning (persists)
oet wait_for_qa_ready disable --subarray_id=1

# bypass the QA wait for the current scan only
oet wait_for_qa_ready override --subarray_id=1