{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/api-evangelist/axonflow/main/json-schema/axonflow-audit-log-entry-schema.json", "title": "AuditLogEntry", "description": "A single audit_logs row as serialized on the wire (orchestrator\nAuditEntry struct). Optional canonical-decision, cross-border and\nsession fields are omitted when empty.\n", "x-generated": "2026-10-09", "x-method": "derived", "x-generator": "derive-json-schema.py", "x-source": "openapi/axonflow-orchestrator-openapi.yml#/components/schemas/AuditLogEntry", "type": "object", "properties": { "id": { "type": "string" }, "request_id": { "type": "string" }, "timestamp": { "type": "string", "format": "date-time" }, "user_id": { "type": "integer" }, "user_email": { "type": "string" }, "user_role": { "type": "string" }, "client_id": { "type": "string" }, "tenant_id": { "type": "string" }, "org_id": { "type": "string" }, "request_type": { "type": "string" }, "query": { "type": "string", "description": "The audited query/prompt (already redacted by the write path)" }, "query_hash": { "type": "string" }, "policy_decision": { "type": "string", "description": "Verdict for the request. Canonical values are allowed, blocked,\nredacted, needs_approval, error; historical rows may carry\nlegacy spellings.\n" }, "policy_details": { "type": "object", "description": "Nested decision detail exactly as the writer stored it\n(policy_ids / reasons / latency_ms plus writer-specific keys\nlike gateway_id, tool_name, decision_id, override_id,\npolicy_matches). Treat keys as writer-specific.\n", "additionalProperties": true }, "provider": { "type": "string" }, "model": { "type": "string", "description": "LLM model identifier the request was routed to (e.g.\n`gpt-4o-mini`, `llama3.2:latest`). Surfaced separately from\n`provider` so callers can filter audit reads by model without\nparsing the provider's vendor-specific naming.\n" }, "response_time_ms": { "type": "integer", "format": "int64", "description": "Measured duration for this row in whole milliseconds. ABSENT when\nthis row's writer measured nothing (#3424).\n\nAbsent is NOT `0`. This field used to be emitted unconditionally, so\nevery row from a writer with no duration to record -- blocked\nrequest / response / media, failed request, workflow, plan and\ntool-call rows, HITL approvals, and the connector-exec MCP closure\n-- carried a literal `0`, which the portal's Latency column rendered\nas a confident \"0ms\". The key is now omitted for those rows rather\nthan set to null: this schema declares no `required` list, so the\nproperty was already optional and a conforming client already\nhandles its absence. Nothing about the declared contract changes.\n\nA `0` that DOES arrive is a real measurement: the column is whole\nmilliseconds, so a decision the platform timed at under 1ms is\nstored as the 0 its clock produced. The portal renders that as\n\"<1ms\" and an absent value as \"-\".\n\nThe quantity differs by `plane`: enforcement duration on\ndecision/gateway/mcp/openai_compat, a PROVIDER round trip on `llm`,\nand a client-asserted OTLP duration on cowork/claude_code (#3431).\nThe compliance summary's `avg_latency_ms` averages only the first.\n" }, "tokens_used": { "type": "integer", "description": "Provider tokens consumed by this request, OMITTED when the row carries no RECORDED provider usage (#3427).\nThe omission says the usage was not recorded; it does NOT assert that no provider was called. Two distinct populations omit it:\n* Rows whose writer never reached a model at all -- a blocked\n request, a redaction, a gateway pre-check deny, a media deny, a\n workflow step, a plan or a tool-call row.\n* Rows written by the LLM RESPONSE-plane block writer, which runs\n AFTER the forward: the call was made and the answer was withheld,\n so a real round trip was paid for, but that writer records none\n of the provider usage it is handed. That is a gap in the writer,\n tracked separately, not a claim about the request.\n\nUntil #3427 both populations left the read paths as a literal `0`, which the portal's detail panel rendered as \"Tokens 0\" under a request no model saw. The key is now omitted for those rows rather than set to null: this schema declares no `required` list, so the property was already optional and a conforming client already handles its absence.\nA `0` that DOES arrive is a real report from a provider, not an absence.\n" }, "cost": { "type": "number", "format": "double", "description": "Estimated provider cost for this request in USD, OMITTED when the row carries no recorded provider usage (#3427). Same rule, same two populations and same rationale as `tokens_used` above; note that `0` is a genuinely representable cost (a locally hosted or free-tier model), which is why absence is expressed by omitting the key rather than by a zero.\n" }, "redacted_fields": { "type": "array", "items": { "type": "string" } }, "error_message": { "type": "string", "description": "Omitted when empty" }, "response_sample": { "type": "string" }, "compliance_flags": { "type": "array", "items": { "type": "string" } }, "security_metrics": { "type": "object", "additionalProperties": true }, "decision_id": { "type": "string", "description": "Canonical decision-row id (#2597/ADR-058); present on planes\nthat mint decisions, omitted on legacy writers\n" }, "plane": { "type": "string", "description": "Enforcement plane that wrote the row (e.g. mcp, llm); omitted on\nlegacy writers. The orchestrator's four ENFORCEMENT planes are\n`orchestrator_request` for /api/v1/process and\n/api/v1/plan/execute, `wcp` for the workflow step gate, `map` for a\nmulti-agent step and `orchestrator_response` for the LLM response.\n(`policy_simulation` and `policy_test` are the orchestrator's too,\nbut they are operator tools rather than enforcement points and\nwrite no decision row.)\n" }, "correlation_id": { "type": "string", "description": "Decision-chain correlation key (#2611); omitted when not stitched" }, "transfer_basis": { "type": "string", "description": "UU PDP Pasal 56 cross-border transfer legal basis (adequacy,\nsafeguards, pasal_56b_dpa, consent) — Enterprise LLM-forward\npath only (#2718)\n" }, "data_residency": { "type": "string", "description": "ISO 3166-1 alpha-2 destination country (#2718); Enterprise only" }, "session_id": { "type": "string", "description": "AI-tool session id (Claude Code / Desktop) forwarded via\nX-Session-Id; asserted attribution, not an auth boundary\n" } } }