DORA Incident Classification Contract v1

Contract ID: CONTRACT-DORA-INCIDENT-CLASSIFICATION-V1-020 Schema version: stella.ops/doraIncidentClassification@v1 Status: Published Owner: Notify engineering owner with regulatory schema owner review Initial legal basis: Commission Delegated Regulation (EU) 2024/1772 Last updated: 2026-04-30

Part of the Stella Ops Contracts index. Audience: implementers who produce or consume DORA incident-classification facts (Notify, Telemetry, Export Center, and the CLI), and reviewers verifying the transport shape against src/.

Purpose

This contract defines the structured DORA major ICT-related incident classification facts carried on IncidentResponse.doraClassification. It adds the seven DORA classification criteria without replacing the existing IncidentResponse.metadata dictionary. Tenant-specific notes and ad-hoc operator fields remain in metadata; regulatory classification facts belong in doraClassification.

The contract does not hardcode customer-specific legal conclusions. Classifier and operator workflows may set nullable thresholdMet values and override audit records, but default incident responses omit doraClassification until DORA facts are available.

Schema Pinning Policy

stella.ops/doraIncidentClassification@v1 is pinned per Stella minor release. The v1 contract is pinned to classification criteria from EU 2024/1772 (DoraClassification.CurrentSchemaVersion / CurrentLegalBasis in src/Notify/StellaOps.Notify.WebService/Contracts/IncidentContracts.cs).

The downstream DORA RTS/template encoder work is implemented and pins its legal sources by explicit package version rather than following latest upstream schema changes automatically. See DoraMajorIncidentReportConstants in src/Notify/__Libraries/StellaOps.Notify.Connectors.Dora/:

The official EBA DPM/XBRL taxonomy package is not yet vendored. Until it is pinned and licensed, EbaPublishedSchemaValidationStatus is blocked and the encoder validates against the local rule set dora-major-incident-report-local-validation-v1 (LocalValidationRuleSetVersion). External schema fetches are disabled per the offline-first posture.

Placement

IncidentResponse gains an optional nullable property:

{
  "incidentId": "incident-dora-1",
  "tenantId": "tenant-dora",
  "eventKind": "dora.incident.opened",
  "status": "open",
  "severity": "critical",
  "title": "Core payment outage",
  "eventCount": 9,
  "firstOccurrence": "2026-04-30T07:00:00Z",
  "lastOccurrence": "2026-04-30T09:30:00Z",
  "metadata": {
    "operatorNote": "free-form metadata stays available"
  },
  "doraClassification": {
    "schemaVersion": "stella.ops/doraIncidentClassification@v1",
    "legalBasis": "EU 2024/1772",
    "classifiedAt": "2026-04-30T09:45:00Z",
    "classifiedBy": "dora-classifier",
    "evidenceRefs": [
      "ledger://notify/dora/opened/incident-dora-1",
      "evidence://telemetry/snapshot/payments-20260430"
    ],
    "clientsAndTransactionsAffected": {
      "thresholdMet": true,
      "affectedClientsCount": 12500,
      "affectedFinancialCounterpartiesCount": 8,
      "affectedTransactionsCount": 42000,
      "affectedTransactionsAmount": 1250000.75,
      "currencyCode": "EUR",
      "rationale": "Payment authorization failures exceeded tenant threshold."
    },
    "reputationalImpact": {
      "thresholdMet": true,
      "publicMediaCoverage": true,
      "recurringClientComplaints": true,
      "regulatorOrPublicAuthorityNotification": false,
      "impactSummary": "Press coverage and client complaints observed.",
      "rationale": "Multiple external signals indicate reputational impact."
    },
    "duration": {
      "thresholdMet": true,
      "startedAt": "2026-04-30T07:00:00Z",
      "endedAt": "2026-04-30T09:30:00Z",
      "incidentDurationMinutes": 150,
      "serviceDowntimeMinutes": 120,
      "rationale": "Downtime exceeded the DORA classification threshold."
    },
    "geographicalSpread": {
      "thresholdMet": true,
      "affectedJurisdictionCodes": ["DE", "FR"],
      "affectedMemberStateCount": 2,
      "crossBorderImpact": true,
      "rationale": "The same service degradation affected two member states."
    },
    "dataLosses": {
      "thresholdMet": false,
      "availabilityLoss": true,
      "authenticityLoss": false,
      "integrityLoss": false,
      "confidentialityLoss": false,
      "recordsAffected": 0,
      "dataCategories": "none",
      "rationale": "No customer data loss was detected."
    },
    "criticalityOfServices": {
      "thresholdMet": true,
      "supportsCriticalOrImportantFunction": true,
      "affectedCriticalServiceIds": ["svc-payments", "svc-auth"],
      "affectedCriticalServiceNames": [
        "Payment authorization",
        "Strong customer authentication"
      ],
      "rationale": "The affected services support critical payment functions."
    },
    "economicImpact": {
      "thresholdMet": true,
      "directCostsAmount": 250000,
      "indirectCostsAmount": 95000.5,
      "grossLossAmount": 345000.5,
      "currencyCode": "EUR",
      "rationale": "Estimated losses exceeded configured reporting threshold."
    },
    "overrides": [
      {
        "criterion": "economicImpact",
        "field": "grossLossAmount",
        "previousValue": "300000.50",
        "newValue": "345000.50",
        "reason": "Finance supplied corrected estimate.",
        "actor": "incident-commander@example.test",
        "overriddenAt": "2026-04-30T10:00:00Z",
        "evidenceRef": "ledger://authority/audit/dora-override-1"
      }
    ]
  }
}

Field Requirements

FieldRequiredDescription
schemaVersionyesAlways stella.ops/doraIncidentClassification@v1.
legalBasisyesInitial value EU 2024/1772; bump only through release schema governance.
classifiedAtnoUTC time the facts were produced or last refreshed.
classifiedBynoClassifier, service, or operator identifier.
evidenceRefsnoImmutable ledger/evidence references needed for offline replay.
clientsAndTransactionsAffectednoCriterion facts for clients, financial counterparts, and transactions affected.
reputationalImpactnoCriterion facts for public, client, authority, or market reputation impact.
durationnoCriterion facts for incident duration and service downtime.
geographicalSpreadnoCriterion facts for affected jurisdictions and cross-border spread.
dataLossesnoCriterion facts for availability, authenticity, integrity, or confidentiality loss.
criticalityOfServicesnoCriterion facts for critical or important functions and affected services.
economicImpactnoCriterion facts for direct, indirect, and gross economic loss.
overridesnoOperator override audit entries with before/after values, reason, actor, time, and evidence reference.

Criterion objects use nullable thresholdMet values. null means the criterion has not yet been assessed or the operator has not supplied enough facts.

Each overrides[] entry records a criterion and field name (free-form strings in the transport contract), the before/after values, the reason, actor, overriddenAt UTC timestamp, and an optional evidenceRef. The deterministic classifier that produces overrides (DoraIncidentClassificationOverrideRequest) supports thresholdMet changes only in v1 (its Field defaults to thresholdMet); the embedded overrides[] shape itself remains generic so later override fields can be recorded without a schema bump.

Implementation Surface (Producers & Consumers)

This contract is the transport projection carried on IncidentResponse. The facts it carries are produced and consumed across several modules:

Backward Compatibility

Replay And Offline Expectations

All values must be derivable from in-repo code, tenant configuration, immutable ledger events, or frozen telemetry/evidence snapshots. Classification replay must not fetch live regulator endpoints, live EBA taxonomy data, or SaaS services.

Deterministic coverage lives in:

Downstream work must keep frozen evidence fixtures beside its own test project and keep fixture hashes stable for repeated replay.