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.roiassurance 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:
tenant-compliance-profile.v1for LEI, legal name, jurisdiction, and DORA financial-entity flags.asset-registry.v1for ICT service and integration asset identities.integrations-dora-roi-metadata.v1for operator-filled contract dates, criticality, and subcontracting-chain provenance.
Evidence scope:
operator-observed-estatecovers ICT services, integrations, software assets, releases, runtime host agents, and direct provider records visible to Stella.operator-suppliedcovers financial-entity identity, outsourcing contract terms, risk decisions, deeper subcontracting-chain facts, and competent-authority filing approvals.stella-suppliermay be attached throughstella-supplier-evidence-v1when Stella itself is part of the operator estate.
Schema Pinning
- Stella contract version:
dora-roi.v1. - EU signing payload registry id:
dora-roi-v1(docs/contracts/eu-signing-payload-registry-v1.md). - Local taxonomy package marker:
its-eu-2024-2956-local-contract-v1. - Runtime library:
src/Findings/__Libraries/StellaOps.Findings.DoraRoi/. - Adjacent tests:
src/Findings/__Tests/StellaOps.Findings.DoraRoi.Tests/. - CLI export/verify commands:
src/Cli/StellaOps.Cli/Commands/DoraRoiCommandGroup.csandsrc/Cli/StellaOps.Cli/Commands/DoraRoiSigningPipelineFactory.cs(CLI adjacent tests undersrc/Cli/__Tests/StellaOps.Cli.Tests/Commands/). - EU signing payload registry entry:
EuSigningPayloadRegistry.DoraRegisterOfInformation(= "dora-roi-v1") insrc/Attestor/StellaOps.Signer/StellaOps.Signer.Core/EuSigningContracts.cs. - ExportCenter assurance profile id
dora.roi(payloaddora-roi-v1,SigningRequired,SupportsOfflineVerification) insrc/ExportCenter/.../AssuranceExports/AssuranceExportProfileRegistry.cs. HTTP produce accepts source-supplied RoI rows through thedoraRoi.registerrequest body and a requireddoraRoi.ownerApprovalRef; the readiness gate clearsdora-roi-register-source-missinganddora-roi-owner-approval-missingonly for that request, while taxonomy and operator signing/storage readiness remain fail-closed configuration checks.
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:
index.json: thedora-roi.v1bundle index shown above.manifest.json: CLI wrapper metadata with schemadora-roi-cli-bundle-manifest.v1(StellaOps.Findings.DoraRoi.DoraRoiBundleManifestassembled byDoraRoiBundleAssembler), artifact typedora-roi-snapshot, payload type iddora-roi-v1, schema pin (schemaPinId)dora-roi.v1, local taxonomy pin (taxonomyPinId)its-eu-2024-2956-local-contract-v1, EBA taxonomy pin (ebaTaxonomyPin)eba-reporting-framework-4.0-taxo-package-4.0-errata5, EBA outer taxonomy ZIP SHA-256 (ebaTaxonomyOuterSha256), the bundleregulatoryConformancelabel,tenantId,reportingYear, bundle hash (bundleHash), canonical index SHA-256 (canonicalIndexSha256), input hash (inputSha256), template count, optional prior-year archive hash (priorYearHash), and a nestedretentionobject (years,retainUntil,sourceoftenant-default/tenant-override, plus optionaloverrideTicketandoverrideReason).inputSha256is computed from the deterministicdora-roi.v1register serialization used by the shared wrapper assembler, not from transport-specific request or file bytes.signature.json: SignerPipeline-produced DSSE envelope wrapper with schemadora-roi-cli-signature.v2, payload type iddora-roi-v1, schema pindora-roi.v1, CLI bundle schema versiondora-roi-cli-bundle.v1, signing algorithm, signing provider, audit id, and theenvelopeobject holding the base64 DSSE payload (canonicalindex.jsonbytes), payload typeapplication/vnd.stellaops.dora.roi.bundle-index.v1+json, and thesignaturesarray. The CLI consumesStellaOps.Findings.DoraRoi.DoraRoiSigningContractas the typed surface shared with the encoder library, so adding this contract here does not introduce a new bundle root.templates/*.xml: deterministic B.01 through B.14 local XML templates.
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:
--year(required): reporting year; the CLI validates it is in 2000-2100 and refuses if it does not match the input register’sreportingYear.--tenant(required): tenant id; must equal the input register’stenant.tenantId.--input(required): path to adora-roi.v1register input JSON file.--output/-o(required): path to write the deterministic signed ZIP.--signing-key-file(required): local HMAC signing-key file.--signing-key-id(optional): signing key identifier recorded in the signature; when omitted a deterministichmac-sha256:<16 hex>fingerprint of the key bytes is used.--taxonomy-package(optional): path to the EBA RoI taxonomy outer ZIP (taxo_package_4.0_errata5.zip). When omitted the CLI probes the vendored repo copy (and theSTELLAOPS_DORA_ROI_TAXONOMY_PACKAGEenvironment override). A taxonomy is always required: if none resolves the export fails closed withDoraRoiTaxonomyLoadException.--prior-year-hash(optional):sha256:<64 lowercase hex>of the previous annual bundle.--prior-year-bundle(optional): previous annual bundle whose archive SHA-256 is bound into the manifest; if both are supplied they must agree.--retention-years(optional, default7): inclusive 5-10. When the value differs from the 7-year default, both--retention-override-ticketand--retention-override-reasonare required.--offline(optional): use the deterministic offline SignerPipeline.--overwrite(optional): overwrite an existing output file.--format text|json/--json: command summary format.
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:
reportingYearsnapshotDatetenantIdleilegalEntityNamejurisdictionCodeisFinancialEntityisSignificantEntitysourceContractVersionstaxonomyPackageVersion
B.02 Functions
One row per function, sorted by functionId:
functionIdfunctionNamedescriptioncriticalityownerTeamRefictServiceCount
B.03 ICT services
One row per ICT service, sorted by functionId, then serviceId:
serviceIdfunctionIdassetIdserviceNameserviceCategoryproviderIdcriticalitydataLocationCountryCode
B.04 ICT services criticality
One row per ICT service, sorted by functionId, then serviceId:
serviceIdfunctionIdproviderIdserviceCriticalitysupportsCriticalOrImportantFunctionfunctionCriticality
B.05 Contractual arrangements
One row per contractual arrangement, sorted by arrangementId:
arrangementIdcontractReferenceproviderIdserviceIdcontractStartDatecontractEndDategoverningLawCountryCodeisIntraGroupannualContractValueEurprovenance
B.06 Intra-group arrangements
One row per arrangement where the contract or provider is intra-group:
arrangementIdproviderIdproviderNameproviderIdentifierproviderCountryCodeserviceIdcontractReferenceintraGroupSource
B.07 Third-party register
One row per provider, sorted by providerId:
providerIdproviderNameproviderIdentifiercountryCodeisIntraGroupparentProviderIdprovenance
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.
arrangementIdserviceIddirectProviderIdrankproviderNameproviderIdentifiercountryCodeprovenance
B.09 Data locations
One row per ICT service, sorted by functionId, then serviceId:
serviceIdfunctionIdassetIdproviderIdproviderCountryCodedataLocationCountryCodesupportsCriticalOrImportantFunction
B.10 Provider locations
One row per direct provider and operator-filled subcontractor location, sorted by providerKind, then providerName, then providerRef:
providerKindproviderRefproviderNameproviderIdentifiercountryCodeprovenance
B.11 ICT service arrangement map
One row per contractual arrangement, sorted by arrangementId:
arrangementIdserviceIdfunctionIdproviderIdproviderNameserviceCriticalityfunctionCriticalitysupportsCriticalOrImportantFunction
B.12 Critical provider concentration
One row per provider, sorted by providerId:
providerIdproviderNameserviceCountcriticalOrImportantServiceCountarrangementCountknownAnnualContractValueEurmaxServiceCriticality
B.13 Operator-fillable provenance
One row per provider, contractual arrangement, and explicit subcontracting-chain source row, sorted by sourceKind, then sourceId:
sourceKindsourceIdarrangementIdrankfieldNameprovenanceisOperatorFillable
B.14 Register summary
One row per register:
reportingYearsnapshotDatetenantIdtemplateCountfunctionCountictServiceCountcontractualArrangementCountthirdPartyProviderCountsubContractingChainRowCountsourceContractVersionstaxonomyPackageVersion
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:
reportingYearis outside the 2025-2100 range. (Note: the CLI’s own--yearguard is the wider 2000-2100; the encoder is the stricter check.)snapshotDateis missing (default value).taxonomyPackageVersionis not the local markerits-eu-2024-2956-local-contract-v1.- The tenant is not marked as a DORA financial entity (
isFinancialEntity). - The tenant id or legal entity name is missing, or the jurisdiction is not an ISO 3166-1 alpha-2 code.
- The LEI fails ISO 17442 validation: an
^[A-Z0-9]{18}[0-9]{2}$shape plus a mod-97 checksum (remainder must equal 1). This mirrors the ISO 17442 mod-97 behavior of the Authority tenant compliance profile validator but is a self-contained reimplementation inDoraRoiValidator.IsValidLei(not shared code with Authority). - ISO country fields (
countryCode,governingLawCountryCode,dataLocationCountryCode, sub-contractingcountryCode) are not uppercase-normalizable alpha-2 codes. - Function, service, provider, or contractual-arrangement ids are missing or duplicated, or required names/categories/contract references are blank.
- A provider’s
parentProviderIdreferences an unknown provider. - Services reference unknown functions or providers.
- Contractual arrangements reference unknown services or providers, or are missing a
contractStartDate. - Contract end dates precede start dates.
- Contract value in EUR is negative.
- Sub-contracting-chain rows reference unknown contractual arrangements.
- Sub-contracting-chain ranks are non-positive or duplicated per arrangement.
- A sub-contracting-chain row uses a provenance other than
operatorFilledorautoCapturedDepth1, or usesautoCapturedDepth1at a rank greater than 1. - An explicit rank-1 sub-contracting-chain row does not match its arrangement’s direct provider (name, identifier, country code) with
autoCapturedDepth1provenance.
Determinism And Offline Replay
- No wall-clock time, random IDs, live web fetches, or regulator endpoints are used by the encoder.
- Dates are formatted as
yyyy-MM-ddwith invariant culture. - Boolean values are
trueorfalse. - Decimal EUR values use two fractional digits with invariant culture.
- Rows are sorted by deterministic ids before encoding.
- Tests assert exact B.01 XML, B.01-B.14 template coverage, row counts, deterministic bundle index ordering, stable output under reordered input, and fail-closed validation behavior.
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):
- Authority tenant compliance profile read boundary for LEI, legal entity name, jurisdiction, and DORA regulated flags.
- Graph asset registry runtime API for ICT service and integration asset identities.
- EvidenceLocker regulatory artifact ledger read boundary for prior-year RoI artifact hashes and signed bundle references.
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:
doraRoi.register: a complete Findings-owneddora-roi.v1register.doraRoi.ownerApprovalRef: the operator/owner approval reference for the source-supplied filing data.- Optional
sourceSnapshotRef,priorYearHash, and retention override fields.
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:
- structurally matches every B.01…B.07 template in the bundle to at least one canonical
b_NN.*.xsdentry inside the loaded taxonomy, - parses every emitted B.01…B.14 template XML on a hardened
XmlReader(DtdProcessing.Prohibit,XmlResolver = null).
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.
