Transport-neutral envelope for ONE unit of non-HTTP work.
Built per work item by the dispatch site (never reused across concurrent
invocations) and handed to every behaviour in the chain. The wrapped handler
keeps its NATIVE argument (IJob, ScheduledJob, (message, metadata),
(conn, data)); only the behaviour chain sees this envelope.
There is deliberately no state slot and no services member: the envelope
is a per-item read-only value, and a behaviour needing a capability closes
over it via its RegistryFactory arm instead. That closed-over capability
is also how a TENANT concern is written: the tenant id is read from
payload and scoped through the ctx-free members of
IMultiTenancyService (getRepositoryFor/prefixCacheKey) — its
IRequestContext-taking members are unreachable from an ingress path,
which carries no request.
kind: IngressKind
Which ingress path produced this work item — the discriminator a behaviour branches on.
name: string
The route the work is addressed by: the queue job name, the scheduler job name, the broker topic, or the WebSocket route path.
The native work item: an IJob, a ScheduledJob, the message payload,
or the frame data.
attempt: number
1-based delivery attempt. Present for 'queue' (from IJob.attempts)
and 'scheduler' (from ScheduledJob.attempts); ABSENT for
'messaging' and 'websocket'. Absent means "this ingress cannot tell
you" — never "first try": brokers redeliver and none tracks a delivery
count, so a fabricated 1 would lie on a fifth redelivery.
headers: Readonly<Record<string, string>>
Transport headers, populated on the 'messaging' arm from
MessageMetadata.headers and on the 'queue' arm from IJob.headers.
{} means the channel carried none; absent means there was no channel.
ABSENT on 'scheduler' deliberately, and that is a statement rather than
an omission: a tick has no upstream request, so there is no header to
carry and no trace to join. Adding the member "for symmetry" would erase
the distinction the three states exist for — an operator could no longer
tell "this work had no cause" from "the cause was lost".
ABSENT on 'websocket' for the different reason that a frame carries no
per-frame headers; the upgrade request's headers are the connection's.