The broker already owns the run. Atlas owns only the brain. For observability, that means Atlas must not invent a new trace when AgentCore invokes it. It must accept the broker's W3C traceparent, then let Pydantic AI's own model span become a child in the same connected server-side trace graph.
The dangerous shortcut is using run_id as a trace key. That would make logs searchable but would not create parent-child trace continuity. pramaan-docs ADR-124 is stricter: technical request identity is trace_id; run_id remains product truth.
agent_invoke.v1 meta
traceparent / tracestate
run_id / form_id / firm_id
|
v
runtime.stream_invoke()
extract traceparent BEFORE contextvars.copy_context()
rehydrate baggage allowlist: run_id, form_id
bind firm_id/model_id/agent.key in local context
|
v
atlas-brain thread
Pydantic AI opens its library-owned gen_ai model span
span trace_id == broker trace_id
span attrs include content-free PRAMAAN pivots
| Surface | Implementation |
|---|---|
runtime.py | Calls agent_invoke_observability_context(...) before contextvars.copy_context(), so the copied brain-thread context carries the remote parent. |
observability.py | Owns extraction, allowlisted baggage rehydration, local firm/model context, the Logfire-lane TracerProvider(id_generator=AwsXRayIdGenerator()), and T2 span enrichment. |
agent.py | Binds model_id/agent.key around each Pydantic AI call without wrapping model calls in manual spans. |
| Static guard | Keeps X-Ray SDK APIs banned, but allows the OTel AwsXRayIdGenerator token only in agents/atlas/observability.py. |
| Standard keys | Custom keys |
|---|---|
service.name, deployment.environment.name, Pydantic AI's content-free gen_ai.operation.name, gen_ai.provider.name, gen_ai.request.model, gen_ai.response.model, gen_ai.usage.*, plus gen_ai.agent.name=Atlas. | agent.key=atlas, firm_id, run_id, form_id, model_id. firm_id is never baggage; only run_id/form_id are baggage. |
gen_ai.input.messages, gen_ai.output.messages, or gen_ai.system_instructions.The new regression test creates a real OTel provider with in-memory export, injects a W3C traceparent, copies context into a separate thread, runs a real Pydantic AI TestModel, and asserts the first gen_ai.operation.name=chat span has the injected trace id plus the expected content-free attributes.
ruff check tests/ scripts/ agents/atlas, uv run pytest tests -q in agents/atlas, root pytest tests -q, scripts/check_brain_egress.py, and git diff --check all pass.