Trace data policy rules (implementation guide)

The ArcFlow trace data policy is mandatory for production deployments. Observability outputs describe what happened (ids, timings, sizes, codes) without exposing what was said (prompts, completions, tool payloads, retrieved text). This page is the implementation and audit guide; Trace data policy covers product context.

The rule applies everywhere traces leak: SDK memory, GET /v1/runs/{id}/trace, Relay trace poll, Postgres arcflow_trace_events, VS Code timeline exports, and optional OTel span attributes (OpenTelemetry export (alpha)).

Allowed field categories

CategoryExamplestrace data policy class
Identifiersrun_id, step_id, trace_id, workflow nameSafe
Names / rolesagent_name, agent_role, tool_name, binding_idSafe if not user PII
Sizesprompt_size_bytes, output_size_bytes, input_size_bytes, chunk_bytesSafe
Countschunk_count, total_bytes, step_count, token deltasSafe
Tokens structtokens.input, tokens.output, tokens.totalSafe
Durationsduration_ms, latency_ms, backoff_msSafe
Error codesworkflow specification error_code, bounded error_messageSafe when no embedded user text
Schema hashesinput_schema_hashSafe
Provider metadataprovider_id, model_id, retry_after_secondsSafe
Status enumsstatus, mode, action on external eventsSafe

Forbidden field categories

CategoryExamplesWhy forbidden
LLM contentPrompt text, system instructions as sent, completion textConversation exfiltration via trace poll
Tool I/OTool argument JSON, tool result payloadsSame as logging raw API bodies
RAG contentRetrieved chunk text, embedding query stringsKnowledge base leakage
CredentialsAPI keys, webhook secrets, tokensCredential exposure
Unbounded PIIFull names, emails, phone numbers in trace fieldsCompliance and browser exposure

If a field could appear in a browser network tab via Relay, treat it as forbidden unless explicitly approved by your deployment policy.

Runtime enforcement

Engine emission is implemented in runtime/arcflow-core/src/tracing/events.rs. Event variants only carry metadata fields. For example:

  • ProviderRequestSent records prompt_size_bytes, not prompt text.
  • ToolCallStarted records input_schema_hash, not arguments.
  • MemoryRetrieved records chunk_count and total_bytes, not chunk bodies.
  • TokenEmitted records numeric deltas, not token strings in stored traces.

Streaming at the SDK layer may expose event.text to your process during run_stream(), but persisted trace rows and HTTP exports remain count-based.

Developer responsibilities

trace data policy is not only an engine concern. Workflow authors must avoid:

MistakeTrace impact
Putting user emails in agent_name or tool_nameNames appear in every step event
Logging result.trace_events alongside raw prompts in app logsBypasses trace policy
Returning retrieved chunks in tool namesAppears in ToolCallStarted
Custom debug flags that dump envelopes to stdoutOut of band leakage

Use neutral agent and tool names. Keep PII in your application database, not in the workflow specification identifiers that emit to trace.

Run results vs traces

GET /v1/runs/{id} result payload may include final output text appropriate to your product policy. The trace data policy governs trace events, not every API field. HITL interrupt objects expose approval_key and expires_at, not transcripts.

Document separately which API fields your compliance team treats as sensitive.

Audit procedure

  1. Sample export: Pull GET /v1/runs/{id}/trace for a RAG and tool-heavy run.
  2. Greppable secrets: Search JSON for @, sk-, Bearer , large base64 blobs.
  3. Field review: Compare each event kind to trace event reference Trace policy column.
  4. Browser path: Repeat via Relay trace URL with a site token.
  5. Logs: Confirm application logs do not duplicate traces with richer content.
  6. OTel (if OpenTelemetry metrics export enabled): Inspect span attributes in Jaeger for prompt or completion keys.

Normative contract: Trace events (normative).

Safe trace excerpt

json
[
 { "kind": "WorkflowStarted", "run_id": "r1", "workflow_name": "demo", "step_count": 2 },
 { "kind": "ProviderRequestSent", "run_id": "r1", "step_id": "s1", "provider_id": "openai", "model_id": "gpt-4o-mini", "prompt_size_bytes": 512 },
 { "kind": "MemoryRetrieved", "run_id": "r1", "step_id": "s1", "agent_name": "researcher", "chunk_count": 5, "total_bytes": 8192 },
 { "kind": "ToolCallCompleted", "run_id": "r1", "step_id": "s1", "tool_name": "search_kb", "duration_ms": 210, "output_size_bytes": 8192 },
 { "kind": "WorkflowCompleted", "run_id": "r1", "duration_ms": 950, "total_tokens": { "input": 120, "output": 45, "total": 165 } }
]

Before shipping new observability features

Checklist for new events, debug endpoints, or dashboard widgets:

  1. Does any field embed user or model text?
  2. Does any field embed tool arguments or retrieval chunks?
  3. Can this event reach the browser via Relay trace poll?
  4. Do logs duplicate trace with richer content?

If any answer is yes, redesign the field or gate behind localhost debug with ARCFLOW_DEBUG=true.