Risk and Incident Classification

Asqav binds two optional regulatory-classification fields into the signed receipt: risk_class, a per-receipt risk tier, and incident_class, a regulatory incident category. risk_class is a controlled vocabulary of low, medium, high, and unknown. incident_class accepts a single token or an array of tokens drawn from supported regime vocabularies (DORA, NYDFS, and CIRCIA), so one receipt can carry a multi-regime classification.

What are risk_class and incident_class?

Both are OPTIONAL caller-supplied fields on POST /api/v1/agents/{id}/sign:

Both fields travel inside the signed envelope, so once a receipt is signed neither value can be mutated without breaking the signature.

The incident_class regime vocabularies

incident_class tokens are drawn from three supported regimes. The cloud rejects any token outside the union of these sets:

An array value lets a single receipt declare, for example, both a DORA category and the CIRCIA covered-cyber-incident token, so an action that triggers reporting obligations under more than one regime carries both classifications in one signed record. Each entry MUST be a non-empty string up to 64 characters and MUST resolve to one of the regime tokens. An empty array is rejected.

Why classify risk and incidents on the receipt?

A signed receipt proves an action happened under a policy. Compliance triage asks two further questions: how risky was this action, and does it fall into a reportable incident category? Without those answers on the receipt, a triage team reconstructs them later from logs and memory, which is exactly the gap that turns a routine review into a forensic exercise.

risk_class lets a producer tier each action at sign time, so a downstream reviewer can filter or escalate by risk without re-deriving it. incident_class lets a producer tag an action against the regulatory categories that drive reporting timelines. An action that maps to a DORA major-incident category or a CIRCIA covered cyber incident is labelled inside the audit chain the moment it is signed.

When a regulator or an internal incident-response team asks "which signed actions fall into category X?", the answer is a query over the receipts, not a manual reconstruction.

Binding both inside the signed envelope means the classification cannot drift after the fact. The risk tier and incident category the producer asserted at sign time are the ones the verifier recovers, cryptographically tied to the action they describe.

Self-declared, cloud-validated shape

risk_class and incident_class are producer-asserted: Asqav signs the values the producer supplies. The cloud validates the SHAPE, not the producer's judgement. For incident_class, the cloud enforces that every token resolves to a supported regime vocabulary and rejects anything outside the union with a machine-readable error. The verbatim guard message takes the form:

text
invalid_incident_class: '<token>' is not in any supported regime vocabulary.

The same guard rejects an empty array (invalid_incident_class: empty list not allowed.) and any entry that is not a non-empty string of length 64 or less. The SDK enforces the same vocabulary client-side and raises before the HTTP roundtrip, so a misclassified token fails fast.

risk_class carries the controlled vocabulary low, medium, high, unknown. The TypeScript SDK types it as exactly those four values. Producers tier the action. Asqav binds the tier into the signed envelope. At the raw wire level the field is an open vocabulary: a deployer classifying against its own risk-management taxonomy MAY instead send a colon-namespaced term such as deployer:financial:medium, which the conformance gate accepts alongside the four standard tokens.

How does this combine with the rest of the receipt?

Both fields are orthogonal to the rest of the payload. A decision receipt that carries a risk tier and a multi-regime incident classification looks like:

json
{
  "action_type": "api:call",
  "receipt_type": "protectmcp:decision",
  "policy_decision": "deny",
  "risk_class": "high",
  "incident_class": ["cybersecurity_related", "circia_covered_cyber_incident"]
}

The signed envelope binds every field. A verifier who later recovers the receipt cannot change the risk tier or either incident token without breaking the signature.

How do I set risk_class and incident_class via the SDK?

Python SDK

python
import asqav

asqav.init()
agent = asqav.Agent.create("risk-emitter")

sig = agent.sign(
    "api:call",
    {"user": "..."},
    compliance_mode=True,
    receipt_type="protectmcp:decision",
    policy_decision="deny",
    risk_class="high",
    incident_class=["cybersecurity_related", "circia_covered_cyber_incident"],
)

A single-regime classification passes a plain string: incident_class="system_failure".

TypeScript SDK

typescript
import { Agent } from "@asqav/sdk";

const agent = Agent.attach({ /* ... */ });

await agent.sign({
  actionType: "api:call",
  context: { user: "..." },
  complianceMode: true,
  receiptType: "protectmcp:decision",
  policyDecision: "deny",
  riskClass: "high",
  incidentClass: ["cybersecurity_related", "circia_covered_cyber_incident"],
});

curl

bash
curl -X POST https://api.asqav.com/api/v1/agents/agt_risk/sign \
  -H "X-API-Key: $ASQAV_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action_type": "api:call",
    "compliance_mode": true,
    "receipt_type": "protectmcp:decision",
    "policy_decision": "deny",
    "risk_class": "high",
    "incident_class": ["cybersecurity_related", "circia_covered_cyber_incident"]
  }'

How does a compliance team use these fields?

A triage team holds the signed receipts and the producer's classification policy. To triage by risk and incident category, the team:

  1. Filters receipts by risk_class to surface the high tier for priority review.
  2. Filters receipts by incident_class token to find actions that map to a reportable category under DORA, NYDFS, or CIRCIA.
  3. Confirms each incident_class token resolves to a real regime category (the cloud guard enforces this at sign time, so an invalid token cannot exist on a valid receipt).
  4. Cross-references the producer's classification policy to confirm the asserted tier and category match the documented rules for that action type.

Each step is a query over the signed record. The classification travels with the action, so triage does not branch into a separate reconstruction exercise.

Related documentation