Skip to main content

Traces and graph

Start with one decision, Guardian, or identity. Follow its links to the rules, controls, tests, and receipts that explain why it exists.

Status: Beta Companion docs: Compliance · SDK observability · Receipts Source of truth: Logs API · Attestation and compliance API.

Trace from any known ID

tree = tr.graph.neighbors(
id="decision_88ab",
depth=4,
direction="both",
include_attestation=True,
)

print(tree.root)
print(tree.nodes)
print(tree.edges)
print(tree.provenance)
print(tree.attestation)

tr.graph.neighbors(...) starts from one node and returns a bounded tree. The service follows the matching policy, identity, asset, and decision-lineage links without making your app know where each node is stored.

Inventory governed assets

Use the graph namespace to list assets without walking every product-specific API:

assets = tr.graph.list_assets(
kind="mcp_server",
limit=100,
)

for asset in assets.items:
print(asset.id, asset.kind, asset.graph_node_id)

Start a new traversal from any returned graph node when you need its Guardian, identity, scope, or policy links.

Crosswalk one control

crosswalk = tr.graph.crosswalk_controls(
"soc2:CC6.1",
framework="soc2",
)

The crosswalk keeps a control lookup separate from a broad neighborhood walk.

Choose a useful depth

A shallow trace is easier to show in an application. A deeper trace is useful during an audit or incident review.

nearby = tr.graph.neighbors(id="nhi_support_bot", depth=2)
review = tr.graph.neighbors(id="guardian-refund-v3", depth=5)

You can restrict the node kinds when the question is narrow:

controls = tr.graph.neighbors(
id="guardian-refund-v3",
depth=4,
kinds=["guardian", "policy_node", "regulatory_control"],
)

Request an attested subgraph

Decision-lineage trees can include a signed attestation envelope:

tree = tr.graph.neighbors(
id="decision_88ab",
depth=4,
include_attestation=True,
)

print(tree.attestation)

The envelope describes the returned subgraph. Receipt verification remains a separate operation.

Keep graph and replay roles clear

Use observability to replay the stored envelope for one governed run. Use the graph to move across related objects.

run = tr.observability.replay("plog_abc123")
tree = tr.graph.neighbors(id=run.log_id, depth=3)

The replay answers, "What happened in this call?" The graph answers, "What is this call connected to?"

Where to go next