Operator eIDAS attestation / agreement-reference (skeleton template)

Status: ADOPTED — approved by explicit manufacturer-of-record instruction; no named attorney identity asserted (label restated 2026-09-15, SPRINT_20260825_016 LRS-19; the seven acknowledgements and every disposition below are unchanged). As of 2026-09-15 every question on this file is closed — the five that had been open since 2026-05-04 were answered in the Customer Agreement draft-review reply (../decisions/customer-agreement-counsel-thread-draft-review-reply.md §4). LRS-15’s runtime guards are implemented: the current loader rejects unsupported schema versions and non-empty signature blocks. These guards do not validate contractual acceptance. Counsel’s Round 3 disposition (../decisions/eidas-counsel-thread-canonical-model-reply.md, 2026-08-23) confirmed the seven acknowledgements as the required minimum content (“These are the acknowledgements already captured in the proposed attestation skeleton”) and pinned the configuration key. Those five items — signature requirement, schema location, wire format, per-environment vs per-tenant, versioning rule — are now closed; see “Counsel decisions on this file” below. (Header corrected 2026-08-23: it previously cited lawyer-request5.md, a file removed in the 2026-05-04 housekeeping that merged it into the thread record.)

Runtime status: IMPLEMENTED 2026-08-23 (SPRINT_20260823_001 EIDAS-CTL-2) as EidasOperatorAttestationLoader in src/Cryptography/StellaOps.Cryptography.Plugin.Eidas/Loading/. The runtime parses JSON, not YAML — see “Counsel decisions on this file” item 4; the YAML below is illustrative of the SHAPE, and the same field names apply. The runtime reads version, operatorId, attestedAt, qtspRelationship.{qtspServiceIdentifier,packVersion} and all seven acknowledgements.*. It also rejects a non-empty signature block; unknown optional fields are accepted and ignored. Purpose: local operator-controlled attestation file that the runtime (Loader 1 / Loader 2 in src/Cryptography/StellaOps.Cryptography.Plugin.Eidas/Loading/) consults before emitting any positive eIDAS claim state. Until this file is present and well-formed, the runtime emits not-claimed:eidas-operator-attestation-not-loaded (renamed from …-operator-agreement-not-loaded by counsel’s Round 3 disposition). Authored: 2026-05-04 Owner: Stella Ops Compliance + Cryptography Guild Loaded by: the operator places this file at the path configured by Eidas:TrustedList:OperatorAgreementAttestationPath. Counsel pinned that exact key on 2026-08-23: “Validate and pin […]; do not silently search for or infer an attestation.” There is no alias and no fallback — a configured path that does not resolve makes the runtime throw, not quietly treat the attestation as absent.

Why this file exists

The reference-only-no-vendoring canonical model adopted in EXEC-20260504-eidas-reference-only-canonical-model.md puts the burden of qualified-service representations on the operator, not on Stella Ops. The runtime can refuse to emit any positive eIDAS claim until the operator has explicitly attested that:

  1. the operator (not Stella Ops) controls the relevant QTSP relationship;
  2. the operator has rights to use the trust-material pack and the per-transaction evidence;
  3. the operator selected the QTSP and the qualified-service profile;
  4. the operator accepts pack-expiry and evidence-revocation handling duties;
  5. the operator will not represent Stella Ops as a QTSP;
  6. the operator is responsible for downstream qualified-service representations;
  7. the operator will preserve pack and evidence audit records.

This template defines the file shape so that the runtime check, operator workflow, and audit trail all converge on the same structured artefact.

Required acknowledgements (counsel-driven minimum content)

The following acknowledgements MUST appear in the attestation file. Each is a discrete operator-authored claim. Lawyer-request5 §4 point 10 asks counsel to confirm or refine this list.

operator controls the QTSP relationship;
operator has rights to use the pack/evidence;
operator selected the QTSP/service;
operator accepts expiry/revocation duties;
operator will not claim Stella Ops is a QTSP;
operator is responsible for downstream qualified-service representations;
operator will preserve pack/evidence audit records.

Counsel confirmed these seven on 2026-08-23 and did not add, remove or reword any of them. The runtime treats absence or an explicit false on any of the seven as operator-attestation-not-loaded, and names the offenders in the diagnostic so the withholding reason reaches the audit record.

Contractual acceptance record (counsel closure item 7)

Counsel’s 2026-08-23 reply requires this file to record authority, explicit acceptance, version and digest — closure item 7 of ../decisions/eidas-counsel-thread-licence-text-and-customer-agreement-reply.md (EIDAS-CTL-6 may be closed only when …). Counsel supplied the wording; it is reproduced here as counsel wrote it, with two substitutions that counsel’s own §6 authorises, both named below.

I confirm that I am authorised to bind [full legal name and registration identifier of Customer]. On behalf of Customer, I accept the Stella Ops Customer Agreement, version [version], SHA-256 [digest], issued by Е-САЛЮШЪНС ЕООД / e-Solutions EOOD, and make the representations and warranties contained in it, including Schedules 1 and 2 as identified in it. I understand that this file records contractual acceptance and is also a technical prerequisite for the positive-state functionality. It is not an attestation, signature or qualified trust service supplied by Stella Ops or by the Licensor.

Include the signatory’s name, title, signature method, date and customer identifier (counsel’s enumeration).

The two substitutions, and their authority. Counsel wrote the block for a standalone “Stella Ops eIDAS Operator Addendum”, because the instrument shape was still open on 2026-08-23. The owner then ruled Q-16 (full-customer-agreement-now, 2026-08-25): there is no standalone addendum — the addendum content is Schedule 1 of the Customer Agreement, and the operator terms are its Schedule 2. So, against counsel’s text: the instrument name becomes the Customer Agreement, and “the representations and warranties contained in that Addendum” becomes “contained in it, including Schedule 1” — the second change is forced by the first, since the warranties now live in a schedule rather than in a separate instrument. Nothing else is altered. Counsel’s own §6 anticipates this case: “For customers already bound by an order form or customer agreement, that agreement should remain the primary contractual record. The runtime attestation is corroborating evidence and a fail-closed operational control.” The agreement carries the same adaptation at its §11.2, so the two documents say the same thing — including the 2026-09-15 correction naming Schedules 1 and 2, since counsel’s §6 warned that “including Schedule 1” must not suggest Schedule 2 is excluded; counsel’s unaltered original stays in the reply, which is the record of what counsel actually wrote.

Counsel’s sentence “this file records contractual acceptance and is also a technical prerequisite for the positive-state functionality” is kept here as written, because on this surface it is literally true — this is the fail-closed runtime file. (The agreement’s §11.2 necessarily drops it: a contract is not a runtime prerequisite.)

Status of the named instrument. The Customer Agreement is issued at 1.0.0, adopted by the manufacturer of record on 2026-09-16. Use the acceptance procedure and the issued-version register to identify the accepted Agreement and Schedule 2 versions and full digests. Populate a contractual reference only when an actual attributable acceptance exists; issuing the instrument did not itself produce one.

What the runtime does with this block: nothing, by design. EidasOperatorAttestationLoader reads version, operatorId, attestedAt, qtspRelationship.{qtspServiceIdentifier,packVersion} and the seven acknowledgements.*; other fields are accepted and ignored. acceptedAgreement.* is not a loader precondition in the current source. Issuance of the Agreement does not change that runtime contract automatically. This local operational attestation is not a substitute for the separate contractual acceptance record.

File shape — JSON is authoritative, the YAML below is explanatory

The machine-readable definition shipped 2026-09-15: eidas-operator-attestation.schema.json (JSON Schema 2020-12, $id pinned to schema version 1), with a valid example at eidas-operator-attestation.example.json. Counsel §4.2 asked for exactly that, and for this template to stop being the sole definition of what the runtime accepts. The runtime remains the authority: the schema documents what EidasOperatorAttestationDocument deserialises and what EidasOperatorAttestationLoader validates. If they ever disagree, the schema is wrong — and EidasAttestationSchemaConformanceTests is what catches it.

The runtime parses JSON. Counsel’s §4.3 disposition (2026-09-15) makes JSON the authoritative submission format for that reason. The YAML block below is explanatory only and is not loadable: it shows the shape and the field names, which are identical in the JSON the runtime accepts. A versioned JSON schema and a valid JSON example ship with the product (LRS-15); when they exist, they — not this block — define what is accepted.

# eidas-operator-agreement-attestation.yaml
# Stella Ops eIDAS operator attestation — local operator-controlled.
# Loaded by Loader 1 alongside the trust-material pack.

version: 1
operatorId: "<operator's stable identifier; opaque to Stella Ops>"
attestedAt: "<ISO-8601 UTC timestamp; signed by operator>"
attestedBy:
  name: "<authorized operator representative>"
  role: "<role / title>"
  contact: "<email or other operator contact>"

qtspRelationship:
  qtspName: "<QTSP legal name>"
  jurisdiction: "<member-state ISO code>"
  qtspServiceIdentifier: "<service-specific identifier from the relevant TSL>"
  packVersion: "<vendor-supplied pack version pin>"
  packExpiryUtc: "<ISO-8601 UTC; operator commits to refresh before this date>"

acknowledgements:
  controlsQtspRelationship: true
  hasRightsToUsePackAndEvidence: true
  selectedQtspAndService: true
  acceptsExpiryAndRevocationDuties: true
  willNotClaimStellaOpsIsAQtsp: true
  responsibleForDownstreamRepresentations: true
  willPreservePackAndEvidenceAuditRecords: true

# Contractual acceptance of the named instrument (counsel closure item 7).
# Accepted-and-ignored by the runtime today — see "Contractual acceptance record"
# above for why it is not a loader precondition. Populate only from an actual
# acceptance record identifying both the Agreement and Schedule 2. The digests
# come from the retained accepted package and its issued-version register.
acceptedAgreement:
  acceptanceRecordId: "<identifier of the separately retained acceptance record>"
  instrument: "Stella Ops Customer Agreement"
  version: "<version as issued, e.g. 1.0.0>"
  sha256: "<digest of that exact issued version>"
  schedule2:
    version: "<version identified by the accepted Agreement>"
    sha256: "<full digest of that identified Schedule 2>"
  acceptedBy:
    name: "<signatory name>"
    title: "<signatory title>"
    signatureMethod: "<how acceptance was recorded>"
    acceptedAt: "<RFC3339 timestamp>"
    customerIdentifier: "<customer legal identifier>"

# Optional but recommended — operator's own legal counsel sign-off pointer.
# Stella Ops does not validate this; it is operator-side audit trail only.
operatorLegalSignOff:
  reviewedBy: "<operator's counsel name or firm; optional>"
  reviewedAt: "<ISO-8601 UTC; optional>"
  reference: "<operator-side reference / ticket number; optional>"

# No operative signature block: the runtime rejects a non-empty block with
# UnsupportedSignature. Use the unsigned operational declaration and retain
# contractual acceptance separately.

Runtime behaviour expected (Loader 1 / Loader 2)

Verified against current source on 2026-09-16: the loader checks schema version 1 before reading acknowledgements and returns UnsupportedVersion for an unsupported numeric version (including missing/default zero). Unparseable JSON remains Unparseable. A non-empty signature block returns UnsupportedSignature; no signature is cryptographically verified.

(Source authority: EidasOperatorAttestationLoader.cs and EidasOperatorAttestation.cs in src/Cryptography/StellaOps.Cryptography.Plugin.Eidas/Loading/; this is source verification, not a deployed-runtime probe.)

What this file is NOT

Counsel decisions on this file (all six closed)

  1. Acknowledgement listCLOSED 2026-08-23. Counsel’s Round 3 disposition confirmed the seven items above unchanged: “These are the acknowledgements already captured in the proposed attestation skeleton.”
  2. Signature requirementCLOSED 2026-09-15 (§4.1). No blanket qualified-signature or algorithm requirement is imposed on this runtime file, provided the binding customer acceptance is reliably established elsewhere: the primary contractual record is the attributable acceptance through checkout, a signed order or another expressly agreed process, and this file is an operational declaration linked to it. Counsel’s caution about the current shape is direct: “A locally editable file that says ‘I am authorised’ and repeats a known Agreement hash should not, by itself, be treated as conclusive evidence that the organisation contracted with the Licensor”, and “do not equate a file remaining solely in the customer’s deployment with an acceptance received through the agreed contracting channel.” The optional signature block is therefore a defect while the runtime ignores it: “Do not silently treat a present but unvalidated signature as assurance. Until verification is implemented, remove the operative signature option or reject unsupported signed attestations.” Execution: SPRINT_20260825_016 LRS-15. Where verification is later implemented, engineering specifies the accepted algorithms, key-to-signatory binding and validation rules — no algorithm or chain is required merely by this file’s contractual role, and none of this changes the separately settled QTSP-material validation requirements.
  3. Schema locationCLOSED 2026-09-15 (§4.2). Publish a versioned JSON schema with the product, together with a valid JSON example. This template stays useful for explanation but stops being the sole definition of what the runtime accepts; schema, example, parser and conformance tests are kept aligned. Counsel marks this as a release-control recommendation, not a claim that contract law requires publishing JSON Schema. Execution: LRS-15.
  4. Wire-formatCLOSED 2026-09-15 (§4.3). JSON is authoritative because JSON is what the runtime parses. The YAML block below is explanatory only and is labelled as such; it is not loadable. Neither format has superior evidential standing — the Bulgarian electronic-document framework addresses the electronic declaration and document, not the serialization. Two operational requirements come with it: preserve the originally submitted bytes alongside any readable representation, never silently converting a document and then claiming its byte-level digest is unchanged; and reject ambiguous or malformed input rather than resolving it in whichever way happens to enable a positive state.
  5. Per-environment vs per-tenantCLOSED 2026-09-15 (§4.4). The boundary is the legal Operator and its scope of responsibility, not the tenant count. One attestation may cover multiple tenants where the same legal Operator assumes the obligations, controls the deployment and holds the necessary rights and authority for the covered material. Where tenants are operated by independent legal entities, use separate attestations or an expressly documented arrangement naming who assumes the obligations and on whose authority — “Do not assume that a shared technical administrator can bind every organisation using the deployment.” For traceability, link each attestation to the Operator, the contractual acceptance record, the deployment, the covered tenant scope and the loaded pack identifier/version. A pack change may require an updated operational attestation without requiring acceptance of a new Customer Agreement where the legal terms are unchanged.
  6. Versioning ruleCLOSED 2026-09-15 (§4.5). version is the attestation schema version only, and confers no permission to accept future schemas. Three version namespaces stay distinct and must not be conflated: the Agreement version (§11 of ../CUSTOMER_AGREEMENT.md), the attestation schema version (this field) and the pack version (qtspRelationship.packVersion). Counsel’s runtime rule: “Missing, malformed or unsupported attestation versions must not enable a positive eIDAS state. Return a specific not-claimed reason. Do not reinterpret an unknown version as version 1, infer missing acknowledgements, or silently approve an unreviewed migration.” Preserve the original file when migrating a recognised older schema, and keep the gate on the positive-state functionality — it does not purport to terminate unrelated rights in already delivered BUSL copies. Execution: LRS-15.

Append-only history

DateAction
2026-05-04Skeleton template authored under lawyer-request5.md §3 document 4 + §4 point 10 (“counsel asked to identify the minimum required contents”). Treats the seven acknowledgements counsel suggested as the working minimum until counsel returns.
2026-09-15All five remaining counsel questions on this file closed (SPRINT_20260825_016 LRS-14), from the Customer Agreement draft-review reply §4: no blanket signature requirement provided binding acceptance is established elsewhere, but the ignored signature block must be rejected rather than silently accepted; publish a versioned JSON schema plus a valid JSON example; JSON is authoritative and the YAML block is explanatory only; the scope boundary is the legal Operator and not the tenant count; and version is the attestation SCHEMA version only, with unknown versions returning a specific not-claimed reason. The two runtime consequences are NOT implemented by this row — they are LRS-15, and this document says so rather than describing behaviour the code does not have.
2026-09-15Counsel closure item 7 executed (SPRINT_20260825_016 LRS-9). Counsel supplied the required acceptance wording on 2026-08-23 (licence-text reply, “Required acceptance wording for Enclosure E”) and it had never reached this template: measured 2026-09-15, rg "authorised to bind" matched only the counsel reply and CUSTOMER_AGREEMENT.md. Added as written, with the instrument name resolved to the Q-16-ruled Customer Agreement under counsel’s own §6 sentence, plus the five signatory fields counsel enumerated and acceptedAgreement.* in the file shape. The loader is deliberately untouched — the fields are accepted-and-ignored, because a precondition would fail closed against existing attestation files and against an instrument still in draft.
2026-08-23Counsel’s Round 3 disposition confirmed the seven acknowledgements and pinned the configuration key; SPRINT_20260823_001 EIDAS-CTL-2 implemented the loader. Template reconciled against the implementation: status header, negative-state rename (agreementattestation), config-key pinning, the runtime-behaviour list (now including the throw-on-unresolvable-path case), and the JSON wire-format assumption. The five remaining pending-counsel items are unchanged and still open.