# Decision Record

Source: https://www.orthalon.com/pl/docs/operations/decision-record

The versioned record every Orthalon control point writes for an AI interaction: what was attempted, what policy decided, what the sensor could see and whether enforcement was confirmed.

Every browser, desktop, gateway, MCP and mobile event is described by the same record, version **1.0**. It is what the console shows, what the event export contains and what SIEM streaming delivers. It never contains a prompt, a file, a matched value or a session title: detected values appear only as placeholders such as `<AWS_KEY_1>`, and every reason is an upper-case code rather than text.

## What the fields mean

### Enforcement outcome

The decision says what policy asked for. The outcome says what became of it.

| Outcome | Meaning |
| :--- | :--- |
| `NOT_REQUIRED` | Nothing had to be stopped: the interaction was allowed, monitored, or sent after a coaching notice. |
| `ATTEMPTED` | The control point tried, but could not see enough of the interaction to say it worked. A partially inspected or disconnected event is never reported as a successful block. |
| `ENFORCED` | The control point applied the control in the path it owns. A browser block is enforced: the page may have other paths to the network. |
| `CONFIRMED` | The control point prevented the action and knows it did not happen. Only an in-path control can say this: the AI gateway or MCP runtime refusing to forward a request, or the Windows host acknowledging that it replaced the clipboard. It requires full coverage. |
| `FAILED` | The control point tried and the control did not take effect, for example a clipboard replacement the operating system refused. |

An empty outcome means the event came from a sensor version that predates the record. It means **not recorded**, never "succeeded".

### Coverage

| Coverage | Meaning |
| :--- | :--- |
| `FULL` | Everything the decision depends on was inspected. |
| `PARTIAL` | Part of it was not, with a reason: `FILE_TOO_LARGE`, `FILE_TYPE_UNSUPPORTED`, `FILE_INSPECTION_PENDING`, `ATTACHMENT_NOT_INSPECTED`, `AGENT_ACTIONS_NOT_OBSERVED`, or the file-analysis service's own code. |
| `NOT_OBSERVED` | The interaction happened where the sensor cannot see content: `DESTINATION_ONLY` (mobile), `CONTENT_NOT_READ` (a file another application opened). |
| `UNSUPPORTED` | The sensor knows it cannot cover this interaction. |

Not observed and partial coverage are limits of what the sensor could see. They are never a finding of no risk.

### Fail mode

`failMode` names the rule that applied when something could not be checked: `FAIL_OPEN` (let through, labelled) or `FAIL_CLOSED` (refused), with `failModeReason`. `NONE` means nothing failed. A policy bypass caused by a downstream error is always labelled; it is never recorded as a clean allow.

### Actor origin

| Origin | Evidence | Typical source |
| :--- | :--- | :--- |
| `HUMAN` | `USER_ACTIVATION`, `STICKY_ACTIVATION`, `OS_INPUT` | The browser page had user activation; a clipboard transfer through the operating system. |
| `AGENT` | `TOOL_CALL`, `DECLARED_BY_CLIENT` | An MCP tool call; a gateway caller that declared an agent id (not verified). |
| `MIXED` | — | Reserved for sensors that observe both. |
| `UNKNOWN` | `NONE`, `AGENTIC_CLIENT` | Gateway calls without a declared agent, desktop application requests, events in a known agentic browser. |

Confidence is between 0 and 1. A human origin is never certain: input dispatched through browser automation also activates a page, so the browser's evidence stays below 1.

### Account class

`account.class` is `CORPORATE`, `PERSONAL`, `EXTERNAL` (an email domain that is neither your organization's nor a consumer domain) or `UNKNOWN`, with how it was established (`account.source`), a confidence and a reason code such as `domain_not_verified` or `consumer_domain`. A policy rule for unknown accounts also applies to external ones, so an external account is never treated more leniently than an unknown one unless a rule names `EXTERNAL`.

### Identity and deduplication

- `eventId` is unique per stored event. `dedupKey` is the same for every delivery of the same sensor event: a retry, an offline sensor sending its queue again, or a replay from the console. Drop repeats by `dedupKey`.
- `observedAt` is when the sensor saw the interaction; `receivedAt` is when Orthalon stored it. An offline sensor's events arrive with an old `observedAt`.
- `provenance` names the sensor, its version, the policy revision that decided and the sensor's own event id.
- `actor.pseudonym` is a stable identifier for the person within your organization that does not reveal who they are. `actor.email` can be suppressed per destination.

## Agentic browsers and AI sidebars

Orthalon lists the agentic browsers and AI sidebars it knows about and states, per action, what a sensor can see. An action that is not observed is reported as **not observed**, never as safe.

| Client | Kind | Typed prompt, paste, upload on AI sites | Built-in assistant panel | Actions the built-in agent takes |
| :--- | :--- | :--- | :--- | :--- |
| Comet (Perplexity) | Agentic browser | Observed with the extension installed | Not observed | Not observed |
| ChatGPT Atlas (OpenAI) | Agentic browser | Observed with the extension installed | Not observed | Not observed |
| Dia (The Browser Company) | Agentic browser | Observed with the extension installed | Not observed | Not observed |
| Opera Neon | Agentic browser | Observed with the extension installed | Not observed | Not observed |
| Copilot in Microsoft Edge | AI sidebar | Observed | Not observed | Not observed |
| Gemini in Chrome | AI sidebar | Observed | Not observed | Not observed |
| Brave Leo | AI sidebar | Observed | Not observed | Not observed |

Browser extensions cannot read a browser's own assistant panel, and an agent driving pages through automation produces input that looks like a person's. Orthalon therefore does not guess these browsers from their user-agent string, which is Chromium's. When a sensor reports one of these clients, the event carries `actor.agenticClient`, its actor origin becomes `UNKNOWN` (even if the sensor saw user activation) and its coverage `PARTIAL` with `AGENT_ACTIONS_NOT_OBSERVED`. Today the desktop app recognizes Comet by its process for application blocking, but no sensor yet labels the browser events that come from inside an agentic browser; until one does, treat browser events from devices where these clients are installed with the limits in this table.

## JSON Schema

The record as delivered to a webhook or Splunk (`schemaVersion` `1.0`). Fields marked as suppressible arrive as `null` when an administrator keeps them out of a destination.

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "urn:orthalon:decision-record:1.0",
  "title": "Orthalon decision record",
  "type": "object",
  "required": ["schemaVersion", "recordType", "eventId", "dedupKey", "observedAt", "receivedAt", "tenant", "decision", "enforcement", "coverage"],
  "properties": {
    "id": { "type": "string", "description": "Same as eventId; kept for searches written before version 1.0." },
    "organizationId": { "type": "string" },
    "receivedAt": { "type": "string", "format": "date-time" },
    "occurredAt": { "type": "string", "format": "date-time", "description": "Same as observedAt." },
    "user": { "type": ["string", "null"], "description": "The user's email. Suppressible (userEmail)." },
    "appDomain": { "type": "string" },
    "decision": { "enum": ["ALLOWED", "REDACTED", "COACHED_SENT", "COACHED_CANCELLED", "BLOCKED", "APPROVAL_REQUESTED"] },
    "direction": { "enum": ["REQUEST", "RESPONSE"] },
    "contentSource": { "type": ["string", "null"], "description": "PROMPT, CLIPBOARD, CLIPBOARD_COPY, FILE_UPLOAD, FILE_DOWNLOAD, FILE_OPEN, PAGE_VISIT, DESKTOP_REQUEST, MCP_TOOL_CALL, MOBILE_DESTINATION, AI_SIDEBAR, AUTH_CONTEXT" },
    "accountType": { "enum": ["UNKNOWN", "PERSONAL", "CORPORATE", "EXTERNAL"] },
    "accountDomain": { "type": ["string", "null"] },
    "policyId": { "type": ["string", "null"] },
    "detectorCount": { "type": "integer", "minimum": 0 },
    "detections": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["type", "count"],
        "properties": {
          "type": { "type": "string" },
          "count": { "type": "integer", "minimum": 1 },
          "confidence": { "type": ["number", "null"], "minimum": 0, "maximum": 1 }
        }
      }
    },
    "redactedExcerpt": { "type": ["string", "null"], "description": "Placeholders only, such as <AWS_KEY_1>." },
    "file": {
      "type": ["object", "null"],
      "properties": {
        "extension": { "type": ["string", "null"] },
        "sizeBytes": { "type": ["integer", "null"] },
        "inspection": { "type": ["string", "null"] },
        "failureCode": { "type": ["string", "null"] }
      }
    },
    "falsePositiveReported": { "type": "boolean" },
    "justificationReason": { "type": ["string", "null"] },
    "schemaVersion": { "const": "1.0" },
    "recordType": { "const": "orthalon.decision" },
    "eventId": { "type": "string" },
    "dedupKey": { "type": "string", "pattern": "^[0-9a-f]{32}$" },
    "observedAt": { "type": "string", "format": "date-time" },
    "tenant": { "type": "object", "required": ["id"], "properties": { "id": { "type": "string" } } },
    "sensor": {
      "type": "object",
      "properties": {
        "surface": { "enum": ["BROWSER", "DESKTOP", "GATEWAY", "MCP", "MOBILE", null] },
        "id": { "type": ["string", "null"] },
        "version": { "type": ["string", "null"] },
        "recordVersion": { "type": ["integer", "null"] },
        "browserContext": { "enum": ["private", "standard", null] }
      }
    },
    "actor": {
      "type": "object",
      "properties": {
        "pseudonym": { "type": ["string", "null"], "pattern": "^act_[0-9a-f]{32}$" },
        "email": { "type": ["string", "null"] },
        "origin": { "enum": ["HUMAN", "AGENT", "MIXED", "UNKNOWN", null] },
        "originConfidence": { "type": ["number", "null"], "minimum": 0, "maximum": 1 },
        "originEvidence": { "enum": ["USER_ACTIVATION", "STICKY_ACTIVATION", "TOOL_CALL", "DECLARED_BY_CLIENT", "AGENTIC_CLIENT", "OS_INPUT", "NONE", null] },
        "agenticClient": { "type": ["string", "null"] }
      }
    },
    "account": {
      "type": "object",
      "properties": {
        "class": { "enum": ["UNKNOWN", "PERSONAL", "CORPORATE", "EXTERNAL"] },
        "source": { "enum": ["MANAGED_POLICY", "EMAIL_DOMAIN", "WORKSPACE_LABEL", "ACCOUNT_LABEL", "IDP", "UNKNOWN", null] },
        "confidence": { "type": ["number", "null"], "minimum": 0, "maximum": 1 },
        "reason": { "type": ["string", "null"], "pattern": "^[a-z][a-z0-9_]{2,63}$", "description": "Why the class was chosen, e.g. domain_not_verified, consumer_domain." },
        "domain": { "type": ["string", "null"] }
      }
    },
    "asset": {
      "type": "object",
      "properties": {
        "appDomain": { "type": "string" },
        "orgAiAppId": { "type": ["string", "null"] }
      }
    },
    "action": {
      "type": "object",
      "properties": {
        "type": { "type": ["string", "null"] },
        "direction": { "enum": ["REQUEST", "RESPONSE"] }
      }
    },
    "detectorCategories": { "type": "array", "items": { "type": "string" } },
    "policy": {
      "type": "object",
      "properties": {
        "id": { "type": ["string", "null"] },
        "ruleId": { "type": ["string", "null"] },
        "revision": { "type": ["string", "null"] }
      }
    },
    "enforcement": {
      "type": "object",
      "required": ["decision", "outcome"],
      "properties": {
        "decision": { "type": "string" },
        "outcome": { "enum": ["NOT_REQUIRED", "ATTEMPTED", "ENFORCED", "CONFIRMED", "FAILED", null], "description": "null: not recorded by the sensor version that sent the event." },
        "failMode": { "enum": ["NONE", "FAIL_OPEN", "FAIL_CLOSED", null] },
        "failModeReason": { "type": ["string", "null"], "pattern": "^[A-Z][A-Z0-9_]{2,63}$" }
      }
    },
    "coverage": {
      "type": "object",
      "required": ["state"],
      "properties": {
        "state": { "enum": ["FULL", "PARTIAL", "NOT_OBSERVED", "UNSUPPORTED", null] },
        "reason": { "type": ["string", "null"], "pattern": "^[A-Z][A-Z0-9_]{2,63}$" }
      }
    },
    "severity": { "enum": ["informational", "low", "medium", "high", "critical"], "description": "A triage hint. A failed or unconfirmed control on a credential ranks highest." },
    "provenance": {
      "type": "object",
      "properties": {
        "sensorId": { "type": ["string", "null"] },
        "sensorVersion": { "type": ["string", "null"] },
        "policyRevision": { "type": ["string", "null"] },
        "clientEventId": { "type": ["string", "null"] }
      }
    }
  }
}
```

## OCSF mapping

A destination set to **OCSF** receives each record as an [OCSF 1.9.0](https://schema.ocsf.io/) **Data Security Finding** (`class_uid` 2006, category Findings, `type_uid` 200601, activity Create) with the `security_control` profile.

| OCSF attribute | From the record |
| :--- | :--- |
| `time` | `observedAt` (milliseconds) |
| `metadata.uid`, `finding_info.uid` | `eventId` |
| `metadata.correlation_uid` | `dedupKey` |
| `metadata.logged_time` | `receivedAt` |
| `severity_id` | `severity` (1 informational … 5 critical) |
| `action_id` | decision: 1 Allowed, 2 Denied (block, cancelled coaching), 4 Modified (redaction), 99 Other (approval) |
| `disposition_id` | outcome: 2 Blocked only when the block was enforced or confirmed; 11 Corrected (redaction), 14 Delayed (approval), 27 Error (failed), 99 "Attempted, not confirmed", 0 Unknown when not recorded |
| `finding_info.types` | `detectorCategories` |
| `finding_info.analytic.uid` | the rule id, or the policy id |
| `data_security.detection_system_id` | 1 Endpoint (browser, desktop), 2 DLP Gateway, 10 Application-Level DLP (MCP) |
| `data_security.data_lifecycle_state_id` | 3 In Use (clipboard), otherwise 2 In Transit |
| `actor.user.uid`, `actor.user.email_addr` | `actor.pseudonym`, `actor.email` |
| `dst_endpoint.hostname` | `appDomain` |
| `unmapped.orthalon` | the full record, so coverage, actor origin and every original id travel with the finding |
