# MQTT QoS lab

This disposable local lab verifies MQTT 5 QoS packet exchanges, offline-session
queueing, and application idempotency with pinned versions:

- Eclipse Mosquitto 2.0.22
- MQTT.js 5.15.2
- Node.js 22 or newer

It binds an anonymous broker only to `127.0.0.1:18883`. Do not expose it to a
shared network or reuse this configuration in production.

From the RunMQTT repository root:

```bash
docker compose -f public/examples/mqtt-qos-lab/compose.yaml up -d
pnpm mqtt:qos-lab
docker compose -f public/examples/mqtt-qos-lab/compose.yaml down
```

The runner creates a unique topic prefix on every invocation and fails if an
expected exchange is missing. Its JSON output records:

1. QoS 0 `PUBLISH`, QoS 1 `PUBLISH/PUBACK`, and QoS 2
   `PUBLISH/PUBREC/PUBREL/PUBCOMP` on the publishing hop.
2. A persistent subscriber disconnect, one QoS 0 and one QoS 1 publish while
   it is offline, and the messages observed after session resumption.
3. Three distinct QoS 1 publishes with the same business event ID, one
   injected consumer failure, and the resulting idempotent business effect.

The duplicate scenario deliberately uses distinct application publishes. Its
MQTT `DUP` flags are false, demonstrating why a consumer must deduplicate by a
stable event or operation ID instead of relying on the transport flag.

## Managed broker profile

`managed-lab.mjs` is the disposable RunMQTT managed-broker profile. It creates
one uniquely named provider Core, two policy templates, and synthetic devices;
then it verifies TLS and WSS connections, QoS 0/1/2, persistent sessions,
retained messages, Last Will, allowed and denied ACL behavior, and a bounded
QoS 1 latency sample. Its `finally` path removes every created resource.

Run it only from an isolated environment that already has the provider
credentials used by RunMQTT:

```bash
MANAGED_LAB_CONFIRM=run-once node public/examples/mqtt-qos-lab/managed-lab.mjs
```

The script never prints provider credentials, Core IDs, device names, topic
names, or payloads. Its JSON output contains only aggregate measurements,
tool versions, the execution timestamp, and cleanup status. The explicit
confirmation variable prevents an accidental provider resource from being
created by a normal `pnpm mqtt:qos-lab` run.

To use another disposable broker, set `QOS_LAB_URL`. Optional
`QOS_LAB_USERNAME` and `QOS_LAB_PASSWORD` variables are passed to the client but
never printed. Controlled failure tests should not run against RunMQTT's shared
public broker because other users and cleanup policies make the result
non-repeatable.
