Skip to main content

Identifiers

You are in the deep end

This page is the identifier contract: who mints request_id, session_id, and correlation_id, and how to query them. The story is on how it hangs together. The public sequence is the request lifecycle.

Which ids the fabric mints, who owns them, and how they show up in Grafana (Loki business events + Tempo spans).

Related: overview · identities · claims and scopes · memory · README observability

Worked examples used below (one jobs run + one chat thread):

FieldJobs exampleChat example
route_idfee_explainfee_explain
Caller / AFD keyidempotency_key = job-fee-explain:v1(AFD builds start key)
request_idreq-f4cfcc86-b8ed-45c7-9a1b-2c3d4e5f6071req-a1b2c3d4-e5f6-0718-9abc-def012345678
session_idjob-19268885-49db-3eb1-a2a9-cf65e30048f7chat-11111111-1111-4111-8111-111111111111
journey_idjob.fee_explainchat.fee_explain
correlation_idcorr-550e8400-e29b-41d4-a716-446655440000corr-7c9e6679-7425-40de-944b-e07fc1f90ae7
trace_id9af5f0a0c9c181acfcd5d0ce42efc599dad8eff12d624d8d61c627fd3d4c9f66

Contents​

#SectionWhat you get
1Pick an idOne-row cheat sheet: which id answers which question
2Id catalogueShape, minter, lifetime for every id
3Jobs — successHappy path sequence + business events
4Jobs — failure & edgesEntitle reject, hydrate fail, graph fail, poll
5Chat — successNew route + follow-up turn
6Chat — failure & edgesClarify, abstain, hydrate fail, graph fail
7Who may mintOwnership swimlane
8SubagentsChild corr- / sub- linkage
9GrafanaLive labels + queries
10Source mapCode pointers

1. Pick an id​

You want to know…UseExample
Did this HTTP call land?request_idreq-f4cfcc86-b8ed-45c7-9a1b-2c3d4e5f6071
Show me this journey in Lokisession_idjob-19268885-49db-3eb1-a2a9-cf65e30048f7 or chat-11111111-1111-4111-8111-111111111111
Did this run finish? Poll / auditcorrelation_idcorr-550e8400-e29b-41d4-a716-446655440000
Group metrics by product pathjourney_idjob.fee_explain / chat.fee_explain
Open the start→loop Tempo treetrace_id9af5f0a0c9c181acfcd5d0ce42efc599

AFD never mints correlation_id. No AR 202 → AFD returns 503 and does not invent one.

UUID-shaped vs not​

KindIdsShape
UUID (dashed)request_id, correlation_id, session_id (chat- / job- / sub-), audit event_idprefix- + 8-4-4-4-12 hex (job-/sub- use name-UUID; others random)
Not UUIDjourney_idjob.fee_explain / chat.fee_explain (route string)
Not UUIDidempotency_keyCaller string, e.g. job-fee-explain:v1
Not UUIDhint_id / option_idShort opaque tokens, e.g. hint-a1b2c3d4
Not UUIDroute_id / route_versionCatalogue ids, e.g. fee_explain @ 2026.08.1
Not UUIDtrace_id / span_idOTel hex (32 / 16), no dashes
Not UUIDSubagent key (whole string)subagent-{corr-UUID}-{stage_id} — embeds a UUID but is not itself one

2. Id catalogue​

IdShapeWho mintsExampleLifetimeUse
request_idreq- + UUIDAFD edge (echo inbound if set); ADP/ACR mint only if header missingreq-f4cfcc86-b8ed-45c7-9a1b-2c3d4e5f6071One channel hop chainMDC / span / Loki before a run exists
session_id (chat)chat- + UUIDAFD when client omits onechat-11111111-1111-4111-8111-111111111111Chat thread (freeze ~45 min)Freeze PK; stickiness
session_id (jobs)job- + name-UUIDAFD from idempotency_key (stable)job-19268885-49db-3eb1-a2a9-cf65e30048f7That jobs freezeFreeze PK; not conversation memory
session_id (subagent)sub- + name-UUIDAFD for subagent-shaped keyssub-3f1a0c2e-8b9d-4e7a-9c1f-2d4e6a8b0c2eChild freezeParent link on audit
idempotency_keyCaller string (jobs); chat: session:route:v1Caller or AFDjob-fee-explain:v1 / chat-11111111-…:fee_explain:v1Dedup startSame key → same correlation_id
correlation_idcorr- + UUIDAR only (uuid4())corr-550e8400-e29b-41d4-a716-446655440000One runStatus poll; audit chain
journey_idjob.{route} / chat.{route}AFD (not unique per call)job.fee_explainMetric bucketLoki + fabric_journey_outcome_total
hint_id / option_idhint- / opt- + tokenAFDhint-a1b2c3d4 / opt-e5f60718Opaque under session_idWire-safe route chips
Subagent keysubagent-{parent_corr}-{stage}ARsubagent-corr-550e8400-…-0000-start_contract_reviewChild idempotencyAFD parses parent corr-
event_idUUIDAudit producers8f14e45f-ceea-467c-9a7e-2b4d8c1a9f3eAppend-only rowAADP ingest
trace_id / span_idOTel hexOpenTelemetry SDK9af5f0a0c9c181acfcd5d0ce42efc599 / 31652c05931fc4b4That distributed traceTempo

route_id / route_version are published catalogue pins (e.g. fee_explain @ 2026.08.1), not runtime-minted ids.


3. Jobs — success​

Happy path: entitle → decide route → hydrate → start → LLM (and tools) → run.graph.completed.

What AFD mints on POST /v1/jobs​

Before decide, AFD attaches three ids (plus OTel trace_id). None of these is correlation_id — that comes later from AR.

IdHow it is madeExampleWhy
request_idEdge filter: echo inbound X-Request-Id, else mint req- + UUIDreq-f4cfcc86-b8ed-45c7-9a1b-2c3d4e5f6071Correlate this HTTP POST across AFD → ADP → AR logs/spans before a run exists
session_idSessionIds.mintJobOrSub(idempotency_key) → job- + name-UUID (deterministic from the key). Subagent keys get sub- insteadjob-19268885-49db-3eb1-a2a9-cf65e30048f7 from key job-fee-explain:v1Freeze / journey key. Same idempotency_key → same session_id (retry-safe). Not a random UUID like chat
journey_idLiteral "job." + route_idjob.fee_explainKPI / business-event bucket. Shared by every run of that route — not unique per call

Caller still supplies idempotency_key (e.g. job-fee-explain:v1) and route_id (e.g. fee_explain). AFD does not mint that key.

StepBusiness event (or span)Ids (example)
Entitlejob.entitlement.acceptedsession_id=job-19268885-…, request_id=req-f4cfcc86-b8ed-45c7-…, journey_id=job.fee_explain, trace_id=9af5f0a0… — no correlation_id
Decidejob.intent.routedsame + route_id=fee_explain — still no correlation_id
Hydrate / startrun.hydrate.succeeded → run.graph.started → job.run.startedcorrelation_id=corr-550e8400-e29b-41d4-a716-446655440000 appears
GraphTempo llm.complete / tool.invokesame start trace_id + session_id + correlation_id
Donerun.graph.completedsession_id=job-19268885-… + correlation_id=corr-550e8400-…
Poll(no business event)GET /v1/jobs/corr-550e8400-e29b-41d4-a716-446655440000

4. Jobs — failure & edges​

ScenarioWhat happensBusiness eventsCaller seesExample
Not entitledDecide not routejob.intent.abstained → job.entitlement.rejected403session_id=job-… present; no corr-…
Hydrate missBad pin / registry 404run.hydrate.failedAFD 503 / AR 422 HYDRATE_FAILEDAFD does not invent corr-550e8400-…
Graph errore.g. loop exceeded stepsrun.graph.started … then run.graph.failedPoll status=failed (recoverable may be true)202 already returned corr-550e8400-…; Loki run.graph.failed
Duplicate idempotency keyReplay job-fee-explain:v1No second robotSame 202 bodySame correlation_id=corr-550e8400-…
Status pollGET /v1/jobs/{corr}(none)Slim status JSONNew request_id=req-…; lookup corr-550e8400-…

5. Chat — success​

New route (first pin)​

StepBusiness event (or span)Ids (example)
Turn inchat.turn.receivedsession_id=chat-11111111-…, request_id=req-a1b2c3d4-e5f6-0718-…, trace_id=dad8eff1… — no correlation_id
Decidejob.intent.routedsame + route_id=fee_explain — still no correlation_id
Start key(AFD local)idempotency_key=chat-11111111-…:fee_explain:v1; journey_id=chat.fee_explain
Hydrate / startrun.hydrate.succeeded → run.graph.started → chat.run.startedcorrelation_id=corr-7c9e6679-7425-40de-944b-e07fc1f90ae7; freeze chat-11111111-… → pin + corr
User replyFR-5 JSON{"session_id":"chat-11111111-…","status":"accepted"} — no route_id / correlation_id on the wire
GraphTempo llm.complete / tool.invoketrace_id=dad8eff1… + session_id + correlation_id=corr-7c9e6679-…
Donerun.graph.completed → chat.run.deliveredsession_id=chat-11111111-… + correlation_id=corr-7c9e6679-…

Follow-up turn (freeze live)​

Skip decide and ACR. Same session_id and correlation_id; new request_id / trace_id for this HTTP call.

StepBusiness event (or span)Ids (example)
Turn inchat.turn.receivedsame session_id=chat-11111111-…; new request_id=req-99aa88bb-ccdd-eeff-0011-223344556677, new trace_id=…
Resume(no decide / no ACR)freeze → existing correlation_id=corr-7c9e6679-… + fee_explain pin
GraphTempo llm.completesession_id=chat-11111111-… + correlation_id=corr-7c9e6679-…
Donerun.graph.completed → chat.run.deliveredsame journey ids; no second corr- mint

6. Chat — failure & edges​

ScenarioWhat happensBusiness eventsUser-facing (example)correlation_id?
ClarifyDecide needs optionschat.intent.clarifiedsession_id=chat-11111111-… + option_id=opt-e5f60718Not started
AbstainNo safe routechat.intent.abstained{"session_id":"chat-11111111-…","status":"abstain"}Not started
Hydrate missPin/registry failrun.hydrate.failedStart fails closedNot invented by AFD
Graph errorLoop / stage throwrun.graph.failedEvents / poll show failedYes if chat.run.started already returned (e.g. corr-7c9e6679-…)
Hints onlyGET .../hints(none required)session_id=chat-11111111-…, hint_id=hint-a1b2c3d4No run

7. Who may mint​

Jobs idempotency_key is caller-owned (e.g. job-fee-explain:v1). trace_id is SDK-owned (AFD preserves inbound traceparent).


8. Subagents​

When a kind=agent stage runs, AR builds:

idempotency_key = subagent-{parent_correlation_id}-{stage_id}
PieceExample
Parent correlation_idcorr-550e8400-e29b-41d4-a716-446655440000
Stagestart_contract_review
Child idempotency keysubagent-corr-550e8400-e29b-41d4-a716-446655440000-start_contract_review
Child session_idsub-3f1a0c2e-8b9d-4e7a-9c1f-2d4e6a8b0c2e (name-UUID of that key)
Child correlation_idcorr-0a1b2c3d-4e5f-6789-abcd-ef0123456789 (new AR mint)

AFD parses parent_correlation_id from the subagent-corr-… pattern for audit. Parent resume packets list child correlation_ids.


9. Grafana​

Login: Grafana in the local otel-lgtm stack (admin / admin).

EventExample labels
job.entitlement.acceptedsession_id=job-19268885-…, request_id=req-f4cfcc86-b8ed-45c7-…, journey_id=job.fee_explain, trace_id=9af5f0a0… — no correlation_id
job.intent.routed+ route_id=fee_explain — still no correlation_id
run.hydrate.succeeded / run.graph.started+ correlation_id=corr-550e8400-…
job.run.startedsession_id=job-19268885-… + correlation_id=corr-550e8400-…
run.graph.completed / run.graph.failedsession_id=job-19268885-… + correlation_id=corr-550e8400-…
{service_name=~"agent-front-door|agent-data-plane|agent-runtime"} | session_id="job-19268885-49db-3eb1-a2a9-cf65e30048f7"
{service_name=~"agent-front-door|agent-data-plane|agent-runtime"} | correlation_id="corr-550e8400-e29b-41d4-a716-446655440000"
{.correlation_id="corr-550e8400-e29b-41d4-a716-446655440000"}

Prefer the trace_id on start events (e.g. 9af5f0a0c9c181acfcd5d0ce42efc599) for the full AFD → ADP → ACR → AR → llm.complete tree — not later status-poll traces.

graph.invoke pausing for a specialist join (waiting_for=subagent) or human_gate is control flow, not a span error. Those spans stay OK and carry waiting_for / stage_id (and subagent_ids when joining). Look for run.graph.waiting, not exception.message.


10. Source map​

ConcernCodeExample mint
request_idagent-front-door/.../RequestIdFilter.javareq-f4cfcc86-b8ed-45c7-9a1b-2c3d4e5f6071
session_idSessionIds.java, JobsService, AssistantServicejob-19268885-… / chat-11111111-…
correlation_idagent-runtime/app/core/agent_core.py _mint_correlation_idcorr-550e8400-e29b-41d4-a716-446655440000
Subagent keyagent-runtime/app/graph/workflow.pysubagent-corr-550e8400-…-start_contract_review
Audit event_idaudit_client.py, AFD AuditEvents8f14e45f-ceea-467c-9a7e-2b4d8c1a9f3e
Business events / journey_idAFD BusinessEvents, AR telemetry.emitjob.fee_explain