DORA Register of Information Contract v1

Contract ID: CONTRACT-DORA-ROI-V1-021 Version: dora-roi.v1 Status: Draft Owner: Findings platform Last updated: 2026-06-22

Part of the Stella Ops Contracts index. Audience: implementers and reviewers working on the Findings DORA Register of Information encoder, its CLI export/verify commands, and the Export Center dora.roi assurance profile.

Purpose

This contract defines the local Stella Ops projection used to encode DORA Register of Information templates for ITS (EU) 2024/2956: B.01 through B.14.

The v1 implementation is a deterministic local contract over:

Evidence scope:

Schema Pinning

The local marker is not an EBA taxonomy package. As of the work recorded in the “EBA XSD Validation Status” section below, the EBA RoI 4.0 errata5 taxonomy package is vendored in-repo and structural B.01…B.07 conformance now runs against it; the encoder still must not fetch schemas at runtime (the taxonomy is loaded from the offline vendored ZIP only).

Bundle Index

The bundle index is deterministic JSON emitted with these top-level fields in this order:

{
  "schemaVersion": "dora-roi.v1",
  "taxonomyPackageVersion": "its-eu-2024-2956-local-contract-v1",
  "reportingYear": 2026,
  "tenantId": "tenant-bank-de",
  "bundleHash": "sha256:<64 lowercase hex>",
  "templates": [
    {
      "templateId": "B.01",
      "fileName": "dora-roi-b01-general-information.xml",
      "displayName": "General information",
      "rowCount": 1,
      "sha256": "sha256:<64 lowercase hex>"
    }
  ]
}

bundleHash is computed from the ordered set of template ids and template hashes. Template hashes are SHA-256 over UTF-8 bytes of the deterministic XML payload.

CLI ZIP Wrapper

stella export dora-roi wraps the local contract output in a deterministic ZIP for offline handoff and verification. The ZIP entries are:

The CLI wrapper is an offline integrity and handoff format. It does not turn the local XML contract into official EBA XBRL and does not submit to a competent authority.

stella export dora-roi requires a SignerPipeline for the actual signing step. The CLI prefers a host-registered ISignerPipeline; with --offline it instead builds a deterministic in-process pipeline (HMAC-SHA256 DSSE signer keyed by --signing-key-file plus canned PoE / release / quota / audit stubs that route through the same StellaOps.Signer.Core.SignerPipeline implementation – DoraRoiSigningPipelineFactory.BuildOfflinePipeline). Without either a host pipeline or --offline the CLI fails closed with DoraRoiSignerPipelineNotConfiguredException; there is no inline-HMAC fallback. Schema validation against the vendored EBA RoI 4.0 errata5 taxonomy package runs after encoding and before signing; non-conformant bundles are refused with DoraRoiSchemaValidationException.

Export command options

stella export dora-roi (wired in CommandFactory under the export group; implementation DoraRoiCommandGroup.BuildDoraRoiExportCommand) takes:

Verify command

stella verify dora-roi <file> (wired in VerifyCommandGroup; implementation DoraRoiCommandGroup.BuildDoraRoiVerifyCommand) verifies a signed bundle offline. It re-reads index.json, manifest.json, and signature.json; recomputes each template SHA-256 and the bundle hash from index.json; cross-checks the manifest schema/payload pins, bundleHash, templateCount, and canonicalIndexSha256; recanonicalizes index.json and compares it to the DSSE payload; and re-runs the HMAC-SHA256 verification over the canonical payload via DefaultHmacAlgorithm (so regional crypto plugins can substitute the implementation). Options: --signing-key-file (required), --signing-key-id (optional, matched against the DSSE signature key id), --json. It returns a non-zero VerificationFailed exit code when any check fails. The verify command does not consult the EBA taxonomy.

Template XML Shape

Each local template artifact uses the same deterministic XML envelope:

<doraRoiTemplate id="B.01" name="General information" schemaVersion="dora-roi.v1" taxonomyPackageVersion="its-eu-2024-2956-local-contract-v1">
  <row ordinal="1">
    <field name="tenantId">tenant-bank-de</field>
  </row>
</doraRoiTemplate>

Writers must preserve declared field order. Empty optional values are emitted as empty field text so row shapes remain stable.

Criticality fields (criticality, serviceCriticality, functionCriticality, maxServiceCriticality) are emitted as the lower-case enum tokens low, medium, high, or critical (DoraRoiCriticalityLevel -> DoraRoiTemplateEncoder.FormatCriticality).

B.01 Through B.14 Rows

B.01 General information

One row per register:

B.02 Functions

One row per function, sorted by functionId:

B.03 ICT services

One row per ICT service, sorted by functionId, then serviceId:

B.04 ICT services criticality

One row per ICT service, sorted by functionId, then serviceId:

B.05 Contractual arrangements

One row per contractual arrangement, sorted by arrangementId:

B.06 Intra-group arrangements

One row per arrangement where the contract or provider is intra-group:

B.07 Third-party register

One row per provider, sorted by providerId:

B.08 Sub-contracting chain

One row per contractual arrangement and ranked provider in the chain, sorted by arrangementId, then rank, then providerName, then providerIdentifier. Rank 1 is the direct ICT third-party provider and is synthesized from the contractual arrangement when the source does not supply an explicit rank-1 row; the synthesized row carries provenance autoCapturedDepth1. Ranks greater than 1 are operator-fillable and must carry operatorFilled provenance. The two supported provenance values are therefore autoCapturedDepth1 (rank 1 only) and operatorFilled.

B.09 Data locations

One row per ICT service, sorted by functionId, then serviceId:

B.10 Provider locations

One row per direct provider and operator-filled subcontractor location, sorted by providerKind, then providerName, then providerRef:

B.11 ICT service arrangement map

One row per contractual arrangement, sorted by arrangementId:

B.12 Critical provider concentration

One row per provider, sorted by providerId:

B.13 Operator-fillable provenance

One row per provider, contractual arrangement, and explicit subcontracting-chain source row, sorted by sourceKind, then sourceId:

B.14 Register summary

One row per register:

Validation

The local encoder (DoraRoiValidator.NormalizeAndValidate) normalizes input (trim, upper-cases LEI / jurisdiction / country codes, sorts collections by id) and then fails closed before output when:

Determinism And Offline Replay

Runtime Source Boundaries

In the implemented v1 path the encoder (DoraRoiTemplateEncoder.EncodeBundle) is pure: it consumes a fully populated DoraRoiRegister supplied by the caller and the CLI reads that register from the --input JSON file. The prior-year linkage is likewise operator-supplied via the CLI --prior-year-hash / --prior-year-bundle options rather than fetched from a service. The following source-owned read boundaries are the intended live wiring and are NOT yet implemented (the encoder does not call them):

Graph is intended to own only the asset registry API. The typed client boundaries for Authority and EvidenceLocker are declared in eu-runtime-api-contracts-v1.md; those lookups remain blocked until the source services publish dedicated read endpoints. The ExportCenter dora.roi assurance profile reflects the same boundary by requiring callers to supply a complete dora-roi.v1 register and owner approval reference in the HTTP produce request; ExportCenter still does not fetch Authority, Graph, or EvidenceLocker rows itself.

HTTP produce status (Sprint 20260616.006)

The Assurance produce endpoint POST /v1/exports/assurance/profiles/dora.roi/runs (scope export.operator) materializes a signed DORA RoI ZIP when the request supplies:

The authenticated tenant id must match doraRoi.register.tenant.tenantId. ExportCenter loads the vendored EBA RoI taxonomy package offline, runs the same DoraRoiTemplateEncoder.EncodeBundle(register, taxonomy) path used by the CLI contract, refuses non-claimed taxonomy conformance, signs the canonical index.json with operator-owned HMAC material from Export:Assurance:DoraRoi:{SigningKeyFile|SigningKey}, and persists the run through the Assurance run/artifact store. The signing key is never accepted from the HTTP request body.

The produced ZIP uses the same dora-roi-cli-bundle-manifest.v1 / dora-roi-cli-signature.v2 wrapper assembled by StellaOps.Findings.DoraRoi.DoraRoiBundleAssembler. The HTTP-only ownerApprovalRef and sourceSnapshotRef inputs are request/readiness metadata; they are not serialized into manifest.json, because the CLI has no matching wrapper fields and deterministic offline HMAC parity requires the same wrapper shape.

Deployed services may set Export:Assurance:DoraRoi:TaxonomyPackagePath to an explicit read-only copy of the pinned EBA outer ZIP. The readiness gate and produce path both validate that configured path; a publish image does not need a full repository tree mounted just to satisfy dora-roi-schema-mapping-missing.

Readiness remains fail-closed. Without request-supplied source rows or approval, the endpoint returns HTTP 409 with dora-roi-register-source-missing and/or dora-roi-owner-approval-missing; without taxonomy or signing configuration it keeps the relevant blocking readiness reasons. The other DORA Assurance profiles (dora.major-incident-report, dora.info-sharing, dora.tlpt-evidence-pack) still return HTTP 422 assurance_export_produce_not_expressible until their own source-supply contracts are wired over HTTP.

EBA XSD Validation Status

Closed for sprints SPRINT_20260430_121_Findings_dora_roi_templates_b01_b07 and SPRINT_20260430_122_Findings_dora_roi_templates_b08_b14 on 2026-05-02.

The EBA RoI taxonomy package eba-reporting-framework-4.0-taxo-package-4.0-errata5 is vendored at docs/contracts/schemas/eu/dora/roi/eba-reporting-framework-4.0/taxo_package_4.0_errata5/taxo_package_4.0_errata5.zip (Gate 5 closed via docs/legal/decisions/REG-20260502-eba-dora-roi-4-0-errata5.md).

StellaOps.Findings.DoraRoi.DoraRoiTaxonomyAsset loads the outer ZIP at host start, verifies its SHA-256 matches the YAML inventory pin (sha256:2cf8a0fe6aadee36a5bf07403d7bd63a43cab96f98fad8251c31938e8242e2fb), opens the inner EBA_XBRL_4.0_Reporting_Frameworks_4.0.0.0.zip in-memory (no permanent extraction; verified sha256:79a72fc2a0a46fed1d017398489ea3efe171c7bcf96da18866bff33c4b1c37f5), and enumerates canonical b_NN.NN.xsd entries. The encoder’s EncodeBundle(register, taxonomy) overload runs DoraRoiTaxonomyValidator after producing the local XML/index, which:

When every check passes the bundle’s runtime regulatory-conformance flag flips from not-claimed (EBA taxonomy not loaded) to claimed-against:eba-reporting-framework-4.0-taxo-package-4.0-errata5. SHA-256 mismatch on the loaded taxonomy fails closed at load time (DoraRoiTaxonomyLoadException) and the bundle retains the not-claimed default. Malformed template XML keeps the flag at the not-claimed default with a typed reason recorded on RegulatoryConformanceReasons.

B.08…B.14 are Stella-Ops-local synthesized aggregations with no published EBA b_NN.*.xsd equivalent under DORA RoI 4.0; the validator enforces XML well-formedness for those templates while requiring B.01…B.07 to each resolve to a canonical EBA XSD entry. Adjacent tests cover the not-claimed default, the claimed flip, the SHA-256 mismatch path, and the malformed-XML path.