Capture Topology
Asqav stamps a capture_topology value on the Audit Pack manifest entry so a verifier or auditor knows HOW the receipt producer observed the action it signed. The field is a controlled vocabulary of five values: in_process_sdk, network_proxy, browser_extension, ebpf_observer, and passive_telemetry. It is producer attribution metadata, recorded on the manifest, never on the signed payload itself.
What is capture_topology?
capture_topology is an OPTIONAL producer-side field on POST /api/v1/agents/{id}/sign. It names the vantage point from which the receipt producer captured the action. The cloud accepts one of six controlled-vocabulary values:
in_process_sdk: the producer is the Asqav SDK running inside the agent process, observing the action at the call site.network_proxy: the producer is a network-layer proxy on the request path, observing the action as it crosses the wire.browser_extension: the producer is a browser extension observing the action in the user-agent.ebpf_observer: the producer is an eBPF probe observing the action at the kernel boundary.passive_telemetry: the producer observes the action after the fact from logs, SIEM events, or other telemetry, not at the call site.
The value is stamped on the Audit Pack manifest entry for the receipt. It does NOT travel inside the signed payload, so it carries no signature obligation of its own. It is attribution metadata the audit surface reads alongside the signed envelope.
Why does the capture path matter?
A signed receipt answers "did the agent perform action X under policy Y?". It does not, on its own, answer "who watched, and from where?". Two receipts for the same action can carry very different trust weight depending on the vantage point that produced them.
An in_process_sdk receipt is emitted at the call site by code the producer controls. A passive_telemetry receipt is reconstructed after the fact from a log stream that may have gaps. A verifier weighing the evidence needs that distinction inside the audit chain, not in a side channel.
capture_topology puts producer attribution into the same audit record the verifier already reads. When an auditor reviews an Audit Pack, the manifest entry tells them whether the receipt came from an in-process emitter, a proxy on the path, a kernel-level probe, or after-the-fact telemetry. That single value lets the auditor calibrate how much independent corroboration each receipt needs.
The passive_telemetry false-attestation guard
passive_telemetry observes after the fact, so it cannot certify that a policy was evaluated, that restraint was applied, that a lifecycle event happened, or that a counterparty acknowledged anything. A receipt that claims any of those while declaring passive_telemetry would be a false attestation: it would assert active enforcement from a vantage point that only watches.
To close that gap, Asqav pins passive_telemetry to the observation receipt types. A capture_topology=passive_telemetry receipt MUST use receipt_type=protectmcp:observation or protectmcp:observation:result_bound. Any other receipt type is rejected before signing. The verbatim guard message is:
false_attestation_guard: capture_topology=passive_telemetry receipts must use receipt_type=protectmcp:observation[:result_bound], not :<offending> (rule 8)
The SDK enforces the same pairing client-side and raises before the HTTP roundtrip, so a misconfigured emitter fails fast instead of producing a receipt the cloud would refuse.
How does this combine with the rest of the receipt?
capture_topology is orthogonal to the wire payload. It is stamped on the manifest entry and surfaced when the Audit Pack is exported. A receipt with full producer attribution looks like:
{
"action_type": "api:call",
"receipt_type": "protectmcp:observation",
"policy_decision": "none",
"capture_topology": "passive_telemetry"
}
The signed envelope binds the payload fields. capture_topology rides on the manifest entry so the auditor reads the observation path next to the signed action without changing what bytes the producer signed.
How do I set capture_topology via the SDK?
Python SDK
import asqav
asqav.init()
agent = asqav.Agent.create("topology-emitter")
sig = agent.sign(
"api:call",
{"user": "..."},
compliance_mode=True,
receipt_type="protectmcp:observation",
capture_topology="passive_telemetry",
)
For an in-process emitter signing a decision receipt, pass capture_topology="in_process_sdk" with receipt_type="protectmcp:decision".
TypeScript SDK
import { Agent } from "@asqav/sdk";
const agent = Agent.attach({ /* ... */ });
await agent.sign({
actionType: "api:call",
context: { user: "..." },
complianceMode: true,
receiptType: "protectmcp:observation",
captureTopology: "passive_telemetry",
});
curl
curl -X POST https://api.asqav.com/api/v1/agents/agt_topology/sign \
-H "X-API-Key: $ASQAV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"action_type": "api:call",
"compliance_mode": true,
"receipt_type": "protectmcp:observation",
"capture_topology": "passive_telemetry"
}'
How does an auditor use capture_topology?
The auditor holds the Audit Pack, which carries the signed receipts plus the manifest entries. To weigh producer attribution, the auditor:
- Reads
capture_topologyfrom the manifest entry for each receipt. - Confirms that any
passive_telemetryreceipt carries an observation receipt type (the guard enforces this at sign time, so a mismatch cannot exist on a valid Audit Pack). - Calibrates corroboration: an
in_process_sdkreceipt sits closest to the action. Apassive_telemetryreceipt is after-the-fact and may warrant cross-checking against another producer. - Cross-references the receipt's signed payload to confirm the action and decision are consistent with the declared capture path.
Each step is independently checkable. The capture path does not change the cryptographic guarantee on the payload. It tells the auditor how much weight to give the observation behind it.