liminal-sdk 0.19.0

Application-facing SDK traits for liminal messaging clients
Documentation
# Rust SDK worker refusals

Workers answer a pushed request with `PushClient::reply` or refuse it with
`PushClient::refuse(correlation_id, code, words)`. `PushWriter` offers both
methods on the same connection. A refusal accepts the closed codes `busy`,
`invalid`, `unavailable`, and `internal`.

The wire-configured words limit is 1024 UTF-8 bytes, preserving a useful
explanation while bounding storage and decoding. Both worker APIs validate the
code and byte length before locking or writing the socket. Invalid data returns
`SdkError::Protocol` with the bound or fault name and no application data.

Worker identities must fit in 993 UTF-8 bytes so a malformed refusal can name
the full station within the same 1024-byte explanation bound. Registration
rejects a longer identity with `worker_station_too_long`; names are never
truncated.

```rust
let request = worker.recv()?;
if let liminal_sdk::PushReceiveOutcome::Frame(request) = request {
    worker.refuse(request.correlation_id(), "busy", "worker is busy")?;
}
```

A Rust conversation caller receives
`SdkError::WorkerRefused { code, words }`. `code` is the worker code without the
`worker_` prefix, and `words` is exact. Display returns those words; Debug
records only the code and the words' byte count. Route admission errors remain
`SdkError::Conversation`. Classification uses the conversation's numeric reason
code, never a prefix in its message.

The existing host-side server push awaiter returns the stable `worker_<code>`
alone through its legacy `PushReplyRefused` error. Routed calls retain the
validated refusal separately so its words reach only the authorised caller.

The [wire fixture](../../docs/wire/worker-refusal.json) pins every code, a maximal
UTF-8 words case, complete worker and caller frames, and an unchanged opaque
reply. Its `0x0401`–`0x0404` conversation reasons map to `worker_busy`,
`worker_invalid`, `worker_unavailable`, and `worker_internal`. The server logs
malformed or reserved-flag replies by fault name without their bytes. A refusal
settles its slot once; duplicate replies are discarded.

Verify the SDK's live TCP pin on a socket-capable host with
`cargo nextest run -p liminal-sdk --features embedded --lib refusal`.