Story 1444: Functions Domain Spans

The functions broker and workers already had trace propagation plumbing. This Story adds the missing PRAMAAN domain spans from the pramaan-docs ADR-124 registry, using only the shared manual_span helper so the ADOT-owned provider remains the only tracing system.

Span Boundaries

SpanKindCall site
functions.agent_queue.enqueueINTERNALWebSocket broker wraps accepted SQS enqueue work.
functions.agent_queue.process_recordCONSUMERExisting clerk worker SQS record span remains in place.
functions.agent_invoke.buildINTERNALExisting broker envelope and trace-carrier build span remains in place.
functions.agent_invoke.callINTERNALClerk worker wraps the actual AgentCore runtime invoke call.
functions.projection_relay.batchCONSUMERExisting projection relay batch span keeps stored trace-context links.
functions.ws_push.deliverCLIENTExisting ws_pusher delivery span extracts the Lambda payload trace context.
functions.error_response.buildINTERNALWebSocket broker errors and shared FastAPI domain errors wrap response construction.

Semconv Check

Standard keys:
  http.response.status_code
  messaging.system
  messaging.operation.name
  messaging.operation.type
  messaging.destination.name
  messaging.batch.message_count

Custom PRAMAAN product keys:
  firm_id
  run_id
  form_id
  matter_id
  agent.key
  event.type

Guardrails

No product module calls raw tracer APIs or constructs a TracerProvider. The helper owns SpanKind, rejects span names outside the closed enum, and accepts only current standard telemetry keys plus approved PRAMAAN product dimensions.

firm_id stays a span attribute only. The patch does not add baggage writes, content capture, prompt text, matter text, filenames, or provider payloads.

Verification

uv run pytest tests/unit/shared/observability/test_manual_span.py tests/unit/test_router_ws.py tests/unit/clerk_worker/test_handler.py tests/unit/clerk_worker/test_runner.py tests/unit/ws_pusher/test_handler.py tests/unit/test_projection_outbox.py tests/integration/test_error_response_envelope.py -q
uv run ruff check src/app_api/router_ws.py src/clerk_worker/runner.py src/shared/errors/http_handler.py src/shared/observability/manual_span.py tests/unit/shared/observability/test_manual_span.py tests/unit/test_router_ws.py tests/unit/clerk_worker/test_runner.py tests/integration/test_error_response_envelope.py
uv run mypy --follow-imports=silent --ignore-missing-imports src/app_api/router_ws.py src/clerk_worker/runner.py src/shared/errors/http_handler.py src/shared/observability/manual_span.py
bash .github/scripts/observability-guardrail-check.sh
git diff --check

Recall: Story 1444 names only PRAMAAN workflow boundaries, not every function, and routes every manual span through the shared helper with registry names and explicit span kinds.