Anatomy of an ExplainBundle
The ExplainBundle is a single JSON document that answers every question about an agent execution: what model was used, why it was selected, what it cost, what it produced, and whether the output was verified.
Fetching an ExplainBundle
curl https://api.hatidata.com/v2/explain/att-001 \
-H "Authorization: ApiKey hd_live_..."
Or via SDK:
bundle = client.explain(attempt_id="att-001")
The Full Structure
{
"attempt_id": "att-001",
"task": {
"id": "task-001",
"project_id": "proj-abc",
"agent_type": "architect",
"task_class": "AuthoritySpec",
"status": "done",
"created_at": "2026-03-28T10:00:00Z"
},
"attempt": {
"id": "att-001",
"status": "completed_verified",
"agent_run_id": "run-xyz-789",
"lease_token": "lease-abc",
"created_at": "2026-03-28T10:00:01Z",
"completed_at": "2026-03-28T10:00:06Z"
},
"model_decision": {
"id": "md-001",
"task_class": "AuthoritySpec",
"primary_model": "deepseek-ai/deepseek-v3.2-maas",
"capability_class": "StrongGeneral",
"fallback_chain": ["claude-4-sonnet-20250514"],
"budget_mode": "normal",
"routing_reason": "vertex_ai_policy_match",
"decided_at": "2026-03-28T10:00:01Z"
},
"invocations": [
{
"id": "inv-001",
"provider": "Deepseek",
"model_id": "deepseek-ai/deepseek-v3.2-maas",
"input_tokens": 4200,
"output_tokens": 1800,
"cached_tokens": 0,
"cost_usd": 0.0031,
"latency_ms": 2340,
"prompt_hash": "sha256:a1b2c3d4e5f6...",
"response_hash": "sha256:f6e5d4c3b2a1...",
"outcome": "success",
"cache_status": "miss",
"called_at": "2026-03-28T10:00:02Z"
}
],
"artifacts": [
{
"id": "art-001",
"memory_key": "proj:abc:api_contract",
"artifact_kind": "ApiContract",
"state": "verified",
"content_hash": "sha256:d4e5f6a1b2c3...",
"produced_by_agent": "Architect",
"produced_in_run_id": "run-xyz-789",
"validation": {
"id": "val-001",
"verifier_type": "schema_validator",
"status": "passed",
"evidence": {
"checks": 12,
"passed": 12,
"findings": []
},
"validated_at": "2026-03-28T10:00:05Z"
}
},
{
"id": "art-002",
"memory_key": "proj:abc:db_schema",
"artifact_kind": "DbSchema",
"state": "schema_valid",
"content_hash": "sha256:b2c3d4e5f6a1...",
"produced_by_agent": "Architect",
"validation": null
}
],
"events": [
{"kind": "attempt_started", "at": "2026-03-28T10:00:01Z", "detail": null},
{"kind": "model_decided", "at": "2026-03-28T10:00:01Z", "detail": "deepseek-v3.2-maas via vertex_ai policy"},
{"kind": "llm_called", "at": "2026-03-28T10:00:02Z", "detail": "4200 input → 1800 output tokens"},
{"kind": "artifact_generated", "at": "2026-03-28T10:00:04Z", "detail": "api_contract + db_schema"},
{"kind": "artifact_validated", "at": "2026-03-28T10:00:05Z", "detail": "schema_validator: 12/12 passed"},
{"kind": "attempt_completed", "at": "2026-03-28T10:00:06Z", "detail": "completed_verified"}
],
"recovery": [],
"totals": {
"cost_usd": 0.0031,
"duration_ms": 5000,
"input_tokens": 4200,
"output_tokens": 1800,
"attempts": 1,
"invocations": 1,
"artifacts_produced": 2,
"artifacts_verified": 1
}
}
Reading the Bundle: Section by Section
Task & Attempt
The task section tells you the intent — what needed to happen. The attempt section tells you this specific execution run.
Key fields to check:
task.task_class— Determines which routing policy was usedattempt.status— Did it complete successfully?attempt.agent_run_id— Links to CoT hash chain for reasoning trail
Model Decision
This is "why this model?" — the routing decision made before the LLM was called.
| Field | What It Tells You |
|---|---|
primary_model | Which model was selected |
capability_class | What capability level the task needed |
budget_mode | Was the budget constrained? (warning = downgraded model) |
routing_reason | Policy match, budget downgrade, or failover |
fallback_chain | What models would have been tried next on failure |
Invocations
Each entry is a single HTTP call to an LLM provider. For a successful attempt, there's usually one invocation. For retries with model failover, there may be multiple.
| Field | What It Tells You |
|---|---|
prompt_hash | SHA-256 of the full prompt — for reproducibility |
response_hash | SHA-256 of the response — for content verification |
cache_status | hit (cached response reused) or miss (fresh LLM call) |
outcome | success, fallback (primary failed, this is the backup), or error |
cost_usd | Exact cost including cache discount |
Artifacts
Every output the agent produced. Each artifact tracks:
- state — Where it is in the lifecycle (declared → generated → schema_valid → verified → pinned)
- content_hash — Immutable content fingerprint
- validation — Whether and how it was verified
schema_valid means the output matches the expected JSON schema. verified means a downstream verifier (test runner, security scanner) approved it. Not all artifacts go through verification — advisory artifacts stop at schema_valid.
Events
The immutable audit trail. Events are append-only — they can never be modified after creation. This is the compliance-grade record.
Recovery
Empty array for successful attempts. For failed attempts that were retried, this section shows the full recovery chain:
"recovery": [
{
"level": "L1",
"action": "retry",
"failure_kind": "ProviderTransient",
"created_at": "2026-03-28T10:00:03Z"
},
{
"level": "L2",
"action": "escalate",
"failure_kind": "InvalidOutputSchema",
"new_model": "claude-4-sonnet-20250514",
"created_at": "2026-03-28T10:00:10Z"
}
]
Totals
Aggregated metrics across all invocations and artifacts. Use this for cost reports and SLA monitoring.
Common Forensic Queries
"Why did this cost so much?"
Check totals.attempts — multiple attempts multiply cost. Check invocations[].cache_status — cache misses are expensive. Check model_decision.budget_mode — constrained mode means the budget was tight.
"Why did it fail?"
Check attempt.status — if terminal_failed, look at recovery[] for the escalation chain. Check the last invocation.outcome — error means the LLM call itself failed.
"Is this output trustworthy?"
Check artifacts[].state — only verified or pinned artifacts have been checked by a downstream verifier. Check artifacts[].validation.evidence for the specific checks that passed.
Next Steps
- Tracing Artifacts to Prompts — Step-by-step forensic debugging tutorial
- Lineage & Explainability — The data model behind ExplainBundles
- Tasks & Attempts — Understanding the attempt lifecycle