Skip to content

Evidence API

Orbit provides a public, versioned read boundary for integrations that need runtime evidence without depending on OrbitEntry internals:

from orbit.evidence import read_family_evidence

evidence = read_family_evidence("request-family-hash")

The current schema identifier is orbit.evidence.v1.

Runtime Adapter Boundary

Extensions can use orbit.extensions to discover the Django runtime adapter and read versioned family_evidence or capture_health resources. The manifest declares only adapter-provided capabilities and Evidence schema versions, without importing optional extensions.

This boundary is read-only. It does not load commercial packages, validate licenses, alter capture, or add work to the request path.

Correlation Scope

Orbit keeps the active request family in task-local context. Logs and LLM watcher entries created during the same synchronous request or async task retain that family hash, so they appear in the same local evidence timeline.

Context is intentionally not propagated across processes, worker queues, or unrelated threads. Use OrbitLogContext when a background operation has an explicit family hash to associate with it. A matching hash shows correlation, not proof that every operation or downstream service was captured.

Why Use It

Direct ORM access exposes Orbit's complete payload schema and couples an integration to internal model details. The Evidence API returns plain Python dictionaries with a small, documented set of normalized fields.

Use it for local debugging extensions, CI helpers, incident tooling, or agent-assisted workflows that need a stable, metadata-first input.

Find a Family Hash

The MCP get_recent_requests tool returns the complete family_hash. A local integration can also select a captured request from python manage.py shell and pass its hash to the Evidence API:

from orbit.evidence import read_family_evidence
from orbit.models import OrbitEntry

request = (
    OrbitEntry.objects.requests()
    .exclude(family_hash=None)
    .latest("created_at")
)
evidence = read_family_evidence(request.family_hash)

Use the full hash. A shortened value copied from a dashboard label may not identify the family.

Family Response

{
  "schema_version": "orbit.evidence.v1",
  "status": "ok",
  "reason": null,
  "family_hash": "abc123",
  "count": 1,
  "truncated": false,
  "evidence_quality": {
    "status": "complete",
    "warnings": [],
    "missing_fields": [],
    "truncated_fields": [],
    "unsupported_entry_types": [],
    "next_actions": []
  },
  "entries": [
    {
      "id": "7fb37d9d-815b-43d5-8e5f-3faed295ef98",
      "type": "request",
      "family_hash": "abc123",
      "fingerprint": null,
      "created_at": "2026-07-23T12:00:00+00:00",
      "duration_ms": 123.4,
      "attributes": {
        "method": "GET",
        "path": "/checkout/",
        "status_code": 200,
        "query_count": 4,
        "duplicate_query_count": 0,
        "had_exception": false
      },
      "truncated_fields": []
    }
  ]
}

status reports whether the read operation succeeded. It does not say that Orbit captured every event needed for a conclusion.

Status Reason Meaning Recommended response
ok null One or more normalized entries were read Check evidence_quality.status before evaluating the result
not_found family_not_found No matching entries are currently stored Verify the full hash, capture settings, pruning, and retention
invalid invalid_family_hash The hash is blank, padded, malformed, or too long Supply a valid full family hash
invalid invalid_limit The limit is outside 1..5000 Retry with a valid limit
unavailable storage_unavailable The Orbit table is not available Verify migrations and the configured storage alias
unavailable read_failed Storage could not be read safely Retry and inspect server logs

Database exception text and storage details are never returned. A not_found response is not proof that an event did not happen.

Evidence Quality

evidence_quality.status is the completeness signal for automated consumers:

Quality Meaning
complete All normalized v1 fields for supported entry types are present and the family did not exceed the requested limit
partial The family was clipped, a field is missing or shortened, or the family contains an entry type not normalized by v1
unavailable The read could not provide evidence to evaluate

The object includes machine-readable warnings, missing_fields, truncated_fields, unsupported_entry_types, and structured next_actions. Each action contains a stable code and concrete parameters. Any nonempty warning list means a consumer must not conclude that a problem is absent.

result = read_family_evidence("abc123")
quality = result["evidence_quality"]

for action in quality["next_actions"]:
    if action["code"] == "retry_with_higher_limit":
        result = read_family_evidence(
            result["family_hash"],
            limit=action["parameters"]["limit"],
        )

if result["status"] != "ok" or result["evidence_quality"]["status"] != "complete":
    # Report the warning and next action; do not emit a passing diagnosis.
    raise RuntimeError("Orbit evidence needs recovery before evaluation")

A complete result only describes normalized request, query, and exception fields in the returned window. Ignore rules, disabled watchers, sampling, or retention may still mean historical events were never captured or are no longer stored.

Action Catalog

Action code Parameters What the consumer should do
provide_valid_family_hash max_chars Obtain the full hash from get_recent_requests or a captured request
use_valid_limit minimum, maximum, default Retry inside the documented bounds
verify_family_hash none Confirm that the full, unshortened hash was supplied
verify_capture_and_retention none Check watcher settings, ignore rules, pruning, and retention
verify_migrations_and_storage none Run Orbit migrations for the configured storage alias
retry_read none Retry the same read after storage recovers
inspect_server_logs none Inspect the host application's logs for the internal read failure
retry_with_higher_limit limit Repeat read_family_evidence with the supplied limit
call_mcp_tool tool, arguments, reason Invoke the named MCP tool with the supplied complete argument object
review_missing_fields fields Treat the listed measurements as unknown and review capture configuration
review_truncated_fields fields Avoid decisions that require the clipped values
do_not_conclude_absence none Do not report a passing or absent diagnosis from this response

Evidence Quality Fragment

{
  "status": "ok",
  "reason": null,
  "evidence_quality": {
    "status": "partial",
    "warnings": ["unsupported_entry_types"],
    "missing_fields": [],
    "truncated_fields": [],
    "unsupported_entry_types": ["log"],
    "next_actions": [
      {
        "code": "call_mcp_tool",
        "parameters": {
          "tool": "create_incident_bundle",
          "arguments": {
            "source_type": "family_hash",
            "source_value": "abc123",
            "format": "json"
          },
          "reason": "unsupported_entry_types"
        }
      },
      {"code": "do_not_conclude_absence", "parameters": {}}
    ]
  }
}

For not_found, invalid, and unavailable, the same quality object uses status: "unavailable" and returns the recovery actions listed above. Surface the reason to the developer; never translate it into "no problem found".

Capture Health Resource

read_capture_health() returns the metadata-only capture_health resource in orbit.evidence.v1. It exposes storage availability, an allowlisted set of effective RECORD flags and sanitized module states. It never includes payloads, SQL, errors or tracebacks. Configuration and module readiness do not prove that an event was captured.

Entry Schema

Normalized attributes by entry type:

Entry type Attributes
request method, path, status_code, query_count, duplicate_query_count, had_exception, traceback_filename
query is_slow, is_duplicate, duplicate_count, database
exception exception_type, request_method, request_path
Other Empty object; the family quality becomes partial and lists the type in unsupported_entry_types

Missing or malformed values are null. Valid zero values remain zero. This distinction matters for automated verification: unknown data is not a passing measurement.

Limits and Ordering

evidence = read_family_evidence("abc123", limit=250)
  • Default limit: 1000
  • Valid range: 1..5000
  • Ordering: created_at, then entry ID
  • Long paths are limited to 2,048 characters
  • Family hashes and fingerprints are limited to 64 characters
  • Other normalized strings are limited to 255 characters
  • Query strings and URL fragments are removed from paths
  • Clipped fields are listed in both the entry and quality metadata

If truncated is true, retry with a higher limit. If the family remains truncated at 5000, follow the returned call_mcp_tool action for create_incident_bundle and treat it as not fully evaluable instead of assuming omitted evidence is irrelevant. Invalid limits are rejected rather than silently clamped.

Safety Boundary

Version 1 never returns:

  • raw payloads;
  • summaries or tags;
  • request headers, cookies, bodies, query strings, or URL fragments;
  • SQL text or parameters;
  • exception messages, tracebacks, or locals;
  • traceback_filename may expose only a Python traceback filename basename, never its directory or traceback text;
  • log messages;
  • mail, cache, storage, user, or session values.

Endpoint paths, exception class names, database aliases, timestamps, IDs, and fingerprints can still be sensitive in some applications. Review your environment and access policy before exporting Evidence API output.

The adapter performs no writes and returns a structured unavailable state instead of propagating storage errors into the host application. Callers must still branch on status and evidence_quality.status.

Compatibility

Fields may be added to orbit.evidence.v1. Consumers must ignore unknown fields. Existing fields will not be removed, renamed, or given a different meaning within v1. A breaking change requires a new schema identifier such as orbit.evidence.v2.

Import the API from orbit.evidence; importing private helpers from orbit.agentic, orbit.watchers, or the model manager is not a stable integration contract.