Story 1437: ws_pusher continues the run trace
This Story closes the last server-side hop between the clerk worker and browser delivery. The clerk worker now injects W3C traceparent/tracestate into the Lambda invoke payload for ws_pusher. The pusher extracts that carrier before calling API Gateway post_to_connection, so the approved functions.ws_push.deliver CLIENT span joins the run trace.
Why
Without this carrier, X-Ray can show the worker and the WebSocket pusher as unrelated work. The product event still has run_id, but run_id is business truth, not trace context. pramaan-docs ADR-124 requires async server-side boundaries to carry traceparent explicitly.
Boundary model
clerk_worker runner
-> inject active W3C trace context
-> clerk_worker handler Lambda invoke payload
-> ws_pusher extracts traceparent / tracestate
-> functions.ws_push.deliver CLIENT span
-> API Gateway post_to_connection
-> browser frame remains run_id-only
What changed
| Surface | Change |
|---|---|
src/clerk_worker/runner.py |
_FramePusher injects the active trace context at the server-side push boundary and passes it separately from the browser frame. |
src/clerk_worker/handler.py |
_push serializes traceparent and optional tracestate as top-level fields on the ws_pusher Lambda payload. |
src/ws_pusher/handler.py |
The pusher extracts the payload carrier and wraps run frames in manual_span(ManualSpanName.WS_PUSH_DELIVER) before post_to_connection. |
Browser frame contract
{
"v": 1,
"type": "run.done",
"run_id": "...",
"payload": {}
}
The browser frame does not receive traceparent, tracestate, trace_id, or span_id. Browser receipt stays run_id-correlation-only for v1.
Semconv check
| Standard keys emitted | Custom PRAMAAN keys emitted |
|---|---|
| None added by this manual span. Transport/library telemetry remains T1 auto-instrumentation owned by ADOT. | run_id, event.type |
No stale standard keys such as
http.method or http.status_code are introduced. No baggage is written; firm_id is not sent to the pusher payload or browser frame.Verification
uv run pytest tests/unit/ws_pusher/test_handler.py \
tests/unit/clerk_worker/test_handler.py \
tests/unit/clerk_worker/test_runner.py \
tests/unit/shared/observability/test_manual_span.py -q
uv run ruff check src/clerk_worker/handler.py src/clerk_worker/runner.py \
src/ws_pusher/handler.py tests/unit/clerk_worker/test_handler.py \
tests/unit/clerk_worker/test_runner.py tests/unit/ws_pusher/test_handler.py \
tests/unit/shared/observability/test_manual_span.py
bash .github/scripts/observability-guardrail-check.sh
git diff --check