See a SIGNET invoice become a Peppol BIS document
SIGNET · Core domain model
Four layers, one dependency stack
The core model. Every entity is defined once and referenced by the layers above it; primitives sit at the foundation and a verifiable record of trust sits at the apex. Extension and profile objects are published separately and are not counted here.
Trust layer
The audit-grade truth every transaction is judged against.
Agent layer
Who may act, under what mandate, and the decisions they take.
Process layer
The full arc from a need to a settled obligation.
Foundation layer
The shared vocabulary every other layer is built from.
Specification
The Canonical Data Model
SIGNET Canonical Data Model
CDM version: v0.1 — the version-stable identity of the model, published at
https://concert.foundation/signet/v0.1/ (§12.3). This is not the repository release
number, and the two move independently.
Release: carried in package.json and CHANGELOG.md, and rendered in the banner of the
published page. This document does not restate it: a version restated by hand is a version
that drifts, which is what happened to the line this one replaces.
Steward: Concert Foundation
Tier: Normative
Licence: CC0 1.0 (public domain dedication)
Status: Published and in force. Changed only under the revision process in §12.2.
About this document
This specification defines the SIGNET Canonical Data Model (CDM) — the common vocabulary for representing procurement and multi-party commerce across a SIGNET network. The CDM is the central normative artifact of the SIGNET standard. Every conforming implementation reads and writes data that is expressible in, and losslessly mappable to, this model.
The CDM is deliberately published under CC0. The vocabulary is meant to be implemented everywhere, by anyone, without friction or attribution burden. Concert Foundation holds no proprietary claim over the model, and stewards it toward governance on the OpenPeppol AISBL pattern: a non-profit steward with multi-stakeholder representation and no single-party control. It is not there yet, and says so. The Standards Committee that will govern normative change is not constituted; until it is, changes that would fall to it are taken under the published bootstrap clause in governance/README.md — reasoned in writing, subject to a stated comment period, recorded as interim resolutions, and reversible by the Committee on the record. The change-control process itself is described in §12.
Field-level definitions in §4–§7 are normative and are changed only under §12.2. What a conformance check actually validates against is the published JSON Schema in schema/; this document and those schemas are maintained by hand against each other, and nothing checks that they agree. Where they disagree that is a defect in one of them, and governance/defects.md records both an instance (D-20) and the absent control (D-21). Comments are invited at hello@concert.foundation.
1. Purpose and design principles
The CDM exists to solve one problem: procurement data today is fragmented across mutually unintelligible standards and proprietary platforms, which prevents both interoperability and the deployment of intelligent agents across organisational boundaries. The CDM is the Rosetta Stone — a single coherent model that bridges the established standards and adds the structures needed for agent-native, governed, decentralised commerce.
The model is governed by eight design principles.
1.1 Reuse before invention. The CDM does not reinvent procurement semantics. Where a concept is well defined by an existing open standard — OCDS for the contracting lifecycle, EN 16931 for invoicing, UBL for document syntax, the EU eProcurement Ontology (ePO) for semantic relationships — the CDM adopts and aligns to it. New structure is introduced only where existing standards are silent, principally around synthetic agents, machine-readable policy, and decentralised identity.
1.2 Standards as profiles, not forks. The CDM is expressed as a coherent superset that profiles existing standards. A SIGNET document can always be projected down to a conforming OCDS release, a Peppol BIS invoice, or an eForms notice, and data arriving in those formats can always be lifted into the CDM. Mapping tables (§8) are normative.
1.3 Agent-native by construction. Human and synthetic agents are first-class parties. The model represents not only what was decided but which agent decided it, under what authority, using which inputs, and with what rationale. Provenance is structural, not an afterthought.
1.4 Identity is decentralised. Parties are identified by stable, resolvable identifiers that may be Decentralised Identifiers (DIDs). Claims about parties — certifications, financial standing, qualifications — are represented as W3C Verifiable Credentials, verifiable independently of any central registry.
1.5 Data sovereignty is explicit. The model distinguishes between an assertion and the right to access the data behind it. Consent and access grants are represented as data, consistent with the Solid data-sovereignty pattern. The CDM never assumes a central data warehouse.
1.6 Policy is data. Procurement rules — eligibility thresholds, evaluation weightings, approval routing, agent mandates — are represented as machine-readable, human-auditable policy objects, not buried in application logic.
1.7 Events are immutable. Every material change is an append-only event with provenance. The current state of any object is a projection over its event history. This makes audit native and tampering evident.
1.8 Linked-data foundation. The canonical serialisation is JSON-LD, giving every object and property a globally unique URI while remaining ordinary JSON to consumers that do not process the semantics. This aligns the CDM simultaneously with OCDS (JSON), W3C VC/DID (JSON-LD), ePO (RDF/OWL), and Solid (RDF).
2. Architectural overview
The CDM is organised into four layers. Each layer builds on the one below.
2.1 Foundation layer — the primitive value types and reference objects used everywhere: identifiers, parties, values, periods, classifications, documents, items, credentials. (§4)
2.2 Process layer — the procurement lifecycle objects, aligned to the OCDS stages of planning, tender, award, contract, and implementation: needs, sourcing events, lots, submissions, evaluations, awards, contracts, orders, catalogues, invoices, obligations, performance records. (§5)
2.3 Agent layer — the structures that make SIGNET agent-native: synthetic agents, capabilities, mandates, agent actions, decisions, and the policy objects that govern them. (§6)
2.4 Trust layer — the cross-cutting governance structures: events, provenance, consent, and audit records that wrap every object in the layers above. (§7)
3. Notation and conformance keywords
The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Field cardinality is shown as: 1 (exactly one, required), 0..1 (optional single), 1..* (one or more, required), 0..* (zero or more). Data types reference the foundation types in §4 or the JSON Schema primitives string, number, boolean, integer, and ISO 8601 date-time.
4. Foundation layer
4.1 Identifier
A typed, scheme-qualified identifier. Every Party, document, and major object carries at least one.
| Field | Type | Card. | Definition |
|---|---|---|---|
scheme | string (URI) | 1 | The identifier scheme, as a URI. Registered schemes include did, gleif:lei, gs1:gln, vat, companies-house, peppol. |
id | string | 1 | The identifier value within the scheme. |
uri | string (URI) | 0..1 | A resolvable URI for the identified entity, where one exists. |
A did-scheme identifier (e.g. did:web:supplier.example.com) makes the Party self-sovereign and resolvable without a central registry (§1.4).
4.2 Party
Any actor in the network. The single most important foundation object. Subtyped by role.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Primary identifier (DID RECOMMENDED). |
identifiers | Identifier[] | 0..* | Additional identifiers (LEI, VAT, GLN, etc.). |
name | string | 1 | Legal or display name. |
roles | string[] | 1..* | One or more of: buyer, supplier, procuringEntity, payer, payee, humanAgent, syntheticAgent, certifier, observer. |
partyType | string | 1 | organization, person, or agent. |
address | Address | 0..1 | Postal/registered address. |
contactPoint | ContactPoint | 0..1 | Contact details. |
credentials | Credential[] | 0..* | Verifiable Credentials held by the Party (§4.7). |
memberOf | Identifier | 0..1 | The organisation a person or agent acts for. |
A Party with partyType: agent is further described by the Agent layer (§6).
4.3 Value
A monetary amount. Aligned to EN 16931 monetary representation.
| Field | Type | Card. | Definition |
|---|---|---|---|
amount | number | 1 | The numeric amount. |
currency | string | 1 | ISO 4217 three-letter code. |
taxIncluded | boolean | 0..1 | Whether the amount is tax-inclusive. |
4.4 Period
| Field | Type | Card. | Definition |
|---|---|---|---|
startDate | date-time | 0..1 | Inclusive start. |
endDate | date-time | 0..1 | Inclusive end. |
durationInDays | integer | 0..1 | Convenience duration where dates are indicative. |
4.5 Classification
A coded classification against a controlled scheme.
| Field | Type | Card. | Definition |
|---|---|---|---|
scheme | string | 1 | e.g. cpv, unspsc, cpvs, gsin. |
id | string | 1 | Code value. |
description | string | 0..1 | Human-readable label. |
4.6 Item
A line item — a unit of what is being bought, offered, ordered, or invoiced.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | string | 1 | Item identifier, unique within its containing object. |
description | string | 1 | What the item is. |
classification | Classification | 0..1 | Primary classification. |
additionalClassifications | Classification[] | 0..* | Further classifications. |
quantity | number | 0..1 | Quantity. |
unit | Unit | 0..1 | Unit of measure (UN/ECE Rec 20) and unit price. |
deliveryLocation | Location | 0..1 | Where the item is delivered. |
4.7 Credential
A reference to a W3C Verifiable Credential asserting a claim about a Party (e.g. ISO 27001 certification, EcoVadis rating, insurance cover).
| Field | Type | Card. | Definition |
|---|---|---|---|
id | string (URI) | 1 | Credential identifier. |
type | string[] | 1..* | VC types, e.g. VerifiableCredential, ISO27001Certificate. |
issuer | Identifier | 1 | DID or identifier of the issuing authority. |
issuanceDate | date-time | 1 | When issued. |
expirationDate | date-time | 0..1 | When it expires. |
credentialSubject | object | 1 | The claims, per the VC data model. |
proof | object | 1 | Cryptographic proof (may be a BBS proof enabling selective disclosure). |
selectiveDisclosure | boolean | 0..1 | Whether the credential supports zero-knowledge selective disclosure. |
4.8 Document
| Field | Type | Card. | Definition |
|---|---|---|---|
id | string | 1 | Document identifier. |
documentType | string | 1 | Coded type (e.g. tenderNotice, evaluationCriteria, signedContract). |
title | string | 0..1 | Title. |
url | string (URI) | 0..1 | Resolvable location. |
hash | string | 0..1 | Content hash (integrity). |
accessGrant | Identifier | 0..1 | Reference to a Consent/access-grant object (§7.3) where access is controlled. |
5. Process layer
The process layer follows the OCDS lifecycle so that any SIGNET process can be projected to a conforming OCDS release. The five OCDS stages — planning, tender, award, contract, implementation — are preserved as the canonical phase model.
5.1 Need (planning stage)
The demand signal that initiates procurement. Equivalent to OCDS planning.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Need identifier. |
title | string | 1 | Short description of the need. |
description | string | 0..1 | Fuller description. |
requestingParty | Identifier | 1 | The Party raising the need. |
budget | Value | 0..1 | Indicative budget. |
classification | Classification | 0..1 | What is needed. |
rationale | string | 0..1 | Why it is needed. |
governingPolicies | Identifier[] | 0..* | Policy objects that constrain this procurement (§6.5). |
5.2 SourcingEvent (tender stage)
A request to the market — RFP, RFQ, ITT, tender, or call-off competition. Equivalent to OCDS tender.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Event identifier. |
title | string | 1 | Title. |
procuringParty | Identifier | 1 | The buyer/procuring entity. |
procedure | string | 1 | Procedure type, e.g. open, restricted, competitiveFlexible, directAward, frameworkCallOff. |
status | string | 1 | planned, active, evaluating, complete, cancelled, withdrawn. |
lots | Lot[] | 0..* | Divisible portions (§5.3). |
items | Item[] | 0..* | What is being sourced. |
value | Value | 0..1 | Estimated value. |
eligibilityCriteria | Policy[] | 0..* | Machine-readable entry criteria (§6.5). |
evaluationCriteria | Policy[] | 0..* | Machine-readable scoring model (§6.5). |
period | Period | 0..1 | Submission window. |
documents | Document[] | 0..* | Tender documents. |
5.3 Lot
A divisible portion of a SourcingEvent that may be awarded independently.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | string | 1 | Lot identifier within the event. |
title | string | 1 | Lot title. |
items | Item[] | 0..* | Items in this lot. |
value | Value | 0..1 | Estimated lot value. |
5.4 Submission
A supplier's response to a SourcingEvent — a bid, tender, quote, or proposal.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Submission identifier. |
sourcingEvent | Identifier | 1 | The event responded to. |
lot | string | 0..1 | The lot, if lot-specific. |
submittingParty | Identifier | 1 | The supplier. |
submittedBy | Identifier | 0..1 | The agent (human or synthetic) that lodged it. |
items | Item[] | 0..* | Offered items with prices. |
value | Value | 0..1 | Total offered value. |
disclosedCredentials | Credential[] | 0..* | Credentials presented, possibly via selective disclosure. |
sealedProof | object | 0..1 | Where sealed-bid cryptography applies, the encrypted submission and proof (§9.3). |
status | string | 1 | draft, submitted, withdrawn, admissible, inadmissible. |
5.5 Evaluation
The scoring of submissions against the evaluation criteria.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Evaluation identifier. |
submission | Identifier | 1 | The submission scored. |
criteria | Policy | 1 | The evaluation model applied. |
scores | Score[] | 1..* | Per-criterion scores with rationale. |
evaluatedBy | Identifier | 1 | The agent (human or synthetic) performing the evaluation. |
result | string | 1 | passed, failed, ranked. |
decision | Identifier | 0..1 | Link to the Decision record (§6.4). |
5.6 Award (award stage)
The decision to award. Equivalent to OCDS award.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Award identifier. |
sourcingEvent | Identifier | 1 | The event. |
awardedParty | Identifier | 1 | The winning supplier. |
value | Value | 1 | Awarded value. |
rationale | string | 0..1 | Award rationale. |
decision | Identifier | 1 | The Decision record supporting the award (§6.4). |
standstillPeriod | Period | 0..1 | Where regulation requires a standstill (e.g. UK Procurement Act). |
5.7 Contract (contract stage)
The binding agreement. Equivalent to OCDS contract.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Contract identifier. |
award | Identifier | 0..1 | The award it derives from. |
parties | Identifier[] | 1..* | Contracting parties. |
title | string | 1 | Contract title. |
value | Value | 1 | Contract value. |
period | Period | 1 | Contract term. |
obligations | Obligation[] | 0..* | Obligations and milestones (§5.10). |
documents | Document[] | 0..* | Signed contract and annexes. |
governingPolicies | Identifier[] | 0..* | Policies governing performance. |
5.8 Order
A call-off or purchase order against a contract or catalogue. Aligned to UBL Order.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Order identifier. |
contract | Identifier | 0..1 | The contract drawn against. |
buyer | Identifier | 1 | Ordering party. |
seller | Identifier | 1 | Supplying party. |
items | Item[] | 1..* | Ordered items. |
value | Value | 1 | Order value. |
deliveryPeriod | Period | 0..1 | Required delivery. |
5.9 Catalogue
A structured offering of goods/services. Aligned to UBL Catalogue and Peppol BIS Catalogue.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Catalogue identifier. |
providerParty | Identifier | 1 | The supplier. |
items | Item[] | 1..* | Catalogue lines with prices. |
validityPeriod | Period | 0..1 | Validity. |
5.10 Obligation
A contractual obligation, deliverable, or milestone with a compliance state.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | string | 1 | Obligation identifier within the contract. |
description | string | 1 | What must be done. |
dueDate | date-time | 0..1 | When. |
responsibleParty | Identifier | 0..1 | Who is responsible. |
status | string | 1 | pending, met, breached, waived. |
evidence | Document[] | 0..* | Evidence of fulfilment. |
5.11 Invoice (implementation stage)
An invoice, fully aligned to EN 16931 so it is convertible to Peppol BIS / UBL Invoice or Factur-X. Field names below reference EN 16931 Business Terms (BT) for traceability.
| Field | Type | Card. | EN 16931 | Definition |
|---|---|---|---|---|
id | Identifier | 1 | BT-1 | Invoice number. |
issueDate | date-time | 1 | BT-2 | Issue date. |
contract | Identifier | 0..1 | BT-12 | Related contract. |
order | Identifier | 0..1 | BT-13 | Related order. |
seller | Identifier | 1 | BG-4 | Seller. |
buyer | Identifier | 1 | BG-7 | Buyer. |
lines | InvoiceLine[] | 1..* | BG-25 | Invoice lines. |
taxTotal | Value | 1 | BG-22 | Total tax. |
payableAmount | Value | 1 | BT-115 | Amount due for payment. |
paymentTerms | string | 0..1 | BT-20 | Payment terms. |
The CDM's EN 16931 alignment is what makes a SIGNET network natively compliant with the EU ViDA cross-border e-invoicing mandate (from July 2030) and the national B2B mandates preceding it.
6. Agent layer
This layer is SIGNET's distinctive contribution. No existing procurement standard represents synthetic agents as first-class, governed, accountable participants. The agent layer does.
6.1 SyntheticAgent
An AI agent operating within the network as a first-class Party (partyType: agent, role syntheticAgent).
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Agent DID. |
name | string | 1 | Agent name. |
operatedBy | Identifier | 1 | The Party accountable for the agent. |
model | string | 0..1 | The underlying model family (model-agnostic; for provenance only). |
capabilities | AgentCapability[] | 1..* | Declared capabilities (§6.2). |
mandate | Identifier | 1 | The Mandate governing the agent (§6.3). |
agentCard | string (URI) | 0..1 | A2A Agent Card location (/.well-known/agent.json). |
6.2 AgentCapability
A declared capability, aligned to the A2A Agent Card model so capabilities are discoverable across organisational boundaries.
| Field | Type | Card. | Definition |
|---|---|---|---|
name | string | 1 | Capability name, e.g. evaluate.submission, negotiate.price. |
description | string | 0..1 | What it does. |
inputSchema | object | 0..1 | Expected input. |
outputSchema | object | 0..1 | Produced output. |
6.3 Mandate
The authority granted to an agent — what it may do, within what limits, and where human approval is required. The structure that bounds an agent's remit, and makes an action outside it visible in the record. A grant-type object (§7.4): its withdrawal is recorded by appending an event, never by mutating the object.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Mandate identifier. |
agent | Identifier | 1 | The agent governed. |
grantedBy | Identifier | 1 | The Party granting authority. |
permittedCapabilities | string[] | 1..* | Capabilities the agent may exercise. |
constraints | Policy[] | 0..* | Hard limits (e.g. max discount, value ceiling). |
approvalThresholds | Policy[] | 0..* | Conditions requiring human-in-the-loop approval. |
scope | object | 1 | Data and entity scope the agent may operate within (sandbox boundary). |
validity | Period | 0..1 | Time bound on the mandate. |
6.4 Decision
A record of a decision taken in the network, by a human or synthetic agent, with the inputs and rationale that produced it. The backbone of accountability.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Decision identifier. |
decisionType | string | 1 | e.g. admissibility, evaluation, award, negotiationMove. |
madeBy | Identifier | 1 | The agent (human or synthetic) that decided. |
underMandate | Identifier | 0..1 | The mandate relied on, where the decider is synthetic. |
inputs | Identifier[] | 0..* | The objects considered (submissions, credentials, policies). |
policiesApplied | Identifier[] | 0..* | The policies applied. |
rationale | string | 1 | Human-readable rationale. |
outcome | object | 1 | The decision outcome. |
humanApproval | Identifier | 0..1 | Where a mandate threshold required it, the approving Party and record. |
provenance | Provenance | 1 | Full provenance (§7.2). |
A Decision record satisfies the "material decision" record-keeping that regulation increasingly requires — including the assessment-summary and decision-record obligations of the UK Procurement Act 2023, and the documentation expectations for AI-assisted evaluation under the EU AI Act.
6.5 Policy
A machine-readable, human-auditable rule. Policies express eligibility criteria, evaluation models, approval routing, agent constraints, and compliance rules. "Rules as code" made concrete.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Policy identifier. |
policyType | string | 1 | eligibility, evaluation, approval, constraint, compliance. |
expressionLanguage | string | 1 | The language the rule is written in, e.g. rego, dmn, cel. |
expression | string | 1 | The executable rule. |
humanReadable | string | 1 | A plain-language statement of the same rule. |
version | string | 1 | Policy version. |
issuedBy | Identifier | 1 | The governing Party. |
The dual requirement — expression (machine-executable) and humanReadable (auditable) — is mandatory. A Policy MUST carry both so that the same rule governs agents and is reviewable by humans.
7. Trust layer
Cross-cutting structures that wrap every object above with auditability, provenance, and consent.
7.1 Event
An append-only record of a material change. The current state of any object is the projection of its ordered Event stream (§1.7).
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Event identifier. |
eventType | string | 1 | e.g. submission.lodged, award.decided, mandate.granted. |
subject | Identifier | 1 | The object the event concerns. |
actor | Identifier | 1 | The Party (human or synthetic) that caused the event. |
timestamp | date-time | 1 | When it occurred. |
payload | object | 0..1 | The change. |
previousEventHash | string | 0..1 | Hash of the prior event, forming a tamper-evident chain. |
provenance | Provenance | 1 | Provenance (§7.2). |
7.2 Provenance
Who or what produced an assertion, when, and from what. Aligned to W3C PROV.
| Field | Type | Card. | Definition |
|---|---|---|---|
generatedBy | Identifier | 1 | The agent or activity that produced the assertion. |
generatedAt | date-time | 1 | When. |
derivedFrom | Identifier[] | 0..* | Source objects. |
usedPolicies | Identifier[] | 0..* | Policies applied. |
signature | object | 0..1 | Cryptographic signature over the assertion. |
7.3 Consent
A data-sovereignty access grant — the right of a named party, for a stated purpose, for a bounded time, to access data held by another party. Expresses the Solid consent pattern as CDM data (§1.5).
| Field | Type | Card. | Definition |
|---|---|---|---|
id | Identifier | 1 | Consent identifier. |
grantor | Identifier | 1 | The party who owns the data. |
grantee | Identifier | 1 | The party granted access. |
resource | Identifier[] | 1..* | The data resources covered. |
purpose | string | 1 | The permitted purpose. |
validity | Period | 1 | Time bound. |
revocable | boolean | 1 | Whether revocable before expiry. |
proof | object | 0..1 | Signed grant. |
purpose is a human-readable statement of the purpose for which access is granted, not a machine-evaluable term. The string interoperates; its evaluation is not defined by this specification. A profile MAY define a purposeCode extension with a codelist appropriate to its jurisdiction or sector (§11).
revocable records whether a grant may be withdrawn. It does not record whether one has been: withdrawal is an event, per §7.4.
7.4 Grant-type objects and withdrawal
Grant-type object. A CDM object that confers authority or permission from one party to another for a bounded period, and whose conferred authority may cease before the end of that period.
7.4.1 In this version the grant-type objects are Consent (§7.3) and Mandate (§6.3). The list is enumerated: a later primitive meeting the definition acquires the obligations below only through an explicit amendment naming it. Open-ended inheritance would let a future proposal's author acquire obligations silently.
7.4.2 Withdrawal is an event, not a field. An implementation MUST NOT mutate a grant-type object to record that its authority has been withdrawn. Withdrawal is recorded by appending an Event (§7.1) whose subject is the grant object. This follows §1.7: current state is the projection of the ordered event stream, not mutable state carried on the object.
7.4.3 Projection rule (normative). A grant-type object G is effective at time T if and only if:
- an event of type
<object>.grantednaming G assubjectprecedes T; and - no event of type
<object>.revokednaming G assubjectprecedes T; and - T falls within G's
validityPeriod.
The effective/not-effective determination MUST be reproducible by a third party from the published event stream alone.
7.4.4 Closed core within eventType. The eventType codelist remains open as an extension space, but the subset published in codelists/eventTypeCore.csv is closed and normative: codes in that subset MUST carry the meanings given there, and MUST NOT be redefined, reused, or narrowed by implementations, extensions, or profiles. A code appears in exactly one of the two files, and consumers take the union. Admission to the closed subset is append-only and occurs only through the change-control process (§12); adding an entry is a minor version, and changing the meaning of an existing entry is a major version.
The initial closed subset is consent.granted, consent.revoked, mandate.granted, mandate.revoked.
No *.expired code exists. Expiry occurs by the clock rather than by any party's act, so an expiry event would have no honest actor — which Event requires — and clause 3 of the projection rule tests validity directly.
7.4.5 No field is added to Consent or Mandate by this section. Event.subject already carries the grant object's identifier, so withdrawal is fully expressible once the event types exist and their meanings are fixed.
8. Standards mapping (normative)
The CDM is a profile-and-bridge over established standards. The following mappings are normative: a conforming implementation MUST be able to transform between the CDM and these formats without loss of the fields defined in the mapping.
| CDM object | Maps to / from | Mapping basis |
|---|---|---|
| Need | OCDS planning | OCDS 1.1 release |
| SourcingEvent, Lot | OCDS tender; eForms notice | OCDS 1.1; eForms |
| Submission | OCDS bid (bid extension); UBL Tender | OCDS bid extension |
| Award | OCDS award | OCDS 1.1 |
| Contract | OCDS contract | OCDS 1.1 |
| Order | UBL 2.3 Order; Peppol BIS Ordering | UBL 2.3 |
| Catalogue | UBL 2.3 Catalogue; Peppol BIS Catalogue | UBL 2.3 |
| Invoice | EN 16931; Peppol BIS Billing; UBL Invoice; Factur-X | EN 16931 semantic model |
| Party | OCDS parties; ePO Agent | OCDS org; ePO |
| Credential | W3C Verifiable Credentials 2.0 | VC data model |
Identifier (did) | W3C DID 1.0 | DID core |
| Provenance | W3C PROV-O | PROV |
| Semantic layer (all) | EU eProcurement Ontology (ePO) | ePO OWL/RDF |
Where a CDM object has no counterpart in a target standard (notably the entire Agent layer when projecting to OCDS), the projection omits it without error, and the reverse lift leaves those fields empty. SIGNET-original structures are always cleanly separable from third-party standards, consistent with the IP & Licensing Policy.
9. Serialisation
9.1 Canonical form. The canonical serialisation is JSON-LD 1.1. Concert publishes the SIGNET @context at a stable URI. Every object type and property resolves to a URI in the SIGNET vocabulary namespace, itself aligned to ePO terms where equivalents exist.
9.2 Plain-JSON consumption. Consumers that do not process linked-data semantics MAY treat CDM documents as ordinary JSON; the @context is ignorable without loss of the document's tree structure. This preserves the low-friction adoption that made OCDS's plain-JSON approach successful.
9.3 Cryptographic envelopes. Where confidentiality is required — sealed-bid submissions (§5.4), selective credential disclosure (§4.7) — the relevant fields carry a cryptographic envelope (zero-knowledge proof, homomorphic ciphertext, or BBS selective-disclosure proof) in place of cleartext, with verification metadata. The envelope formats are specified in the separate SIGNET Cryptographic Profiles document.
10. Identifiers and namespaces
10.1 Every CDM object MUST carry a network-unique id. Decentralised Identifiers (DIDs) are RECOMMENDED for Parties and agents; URN or URI identifiers are acceptable for process objects.
10.2 The SIGNET vocabulary namespace, the published @context, and the registry of identifier schemes and codelists are maintained by Concert at stable URIs under the concert.foundation domain and MUST NOT be repurposed by implementers to publish non-conforming extensions under the SIGNET name.
11. Extension mechanism
The CDM is extensible without forking, following the OCDS extension pattern.
11.1 An extension is a published, versioned package that adds object types, fields, or codelist values under its own namespace. Extensions MUST NOT redefine or remove core fields.
11.2 Community extensions MAY be submitted to Concert for review and, if broadly useful, promotion into the core model through the change-control process (§12). This keeps the core lean while allowing domain-specific elaboration (e.g. a defence-procurement extension, a construction extension).
11.3 Core conformance (§13) is assessed against the core model only; extensions are conformance-assessed separately.
12. Versioning and change control
12.1 The CDM uses semantic versioning. The major version changes only on a breaking change to the core model; minor versions add backward-compatible structure; patch versions clarify without changing meaning.
12.2 As a normative artifact, the core model changes only through the formal revision process, which requires a recorded resolution, a stated comment period of at least fourteen calendar days, and an approving review. Non-normative material (examples, guidance, mapping notes) MAY be updated under a single approving review with no comment period, consistent with the normative/non-normative distinction in the governance model. The process is recorded in GOVERNANCE.md and took effect on 20 August 2026; changes merged before that date followed prior practice, and governance/reviews/2026-08-normative-approval-audit.md records what that practice was. No Standards Committee is constituted: until one is, decisions that would fall to it are taken under the bootstrap clause in governance/README.md and recorded as interim resolutions.
12.3 Every published version is permanently retrievable at a version-stable URI. Implementations declare the CDM version they target.
13. Conformance
13.1 A document conforms to the CDM if it validates against the published SIGNET JSON Schema for its declared version and satisfies the structural rules in this specification.
13.2 An implementation conforms if it (a) reads and writes conforming documents, (b) performs the normative standards mappings in §8 without loss of mapped fields, and (c) preserves provenance and event integrity for every material change it makes.
13.3 Conformance is verified against the SIGNET conformance test suite (a separate normative artifact, Apache-2.0 licensed) and its synthetic test datasets (CDLA-Permissive). Certification of conformance, and the "SIGNET Certified" mark, are administered by Concert under the IP & Licensing Policy, on identical terms to all implementers.
Appendix A — Worked example (illustrative)
A minimal award Decision made by a synthetic evaluation agent, in canonical JSON-LD (abbreviated):
{
"@context": "https://concert.foundation/signet/v0.1/context.jsonld",
"type": "Decision",
"id": { "scheme": "did", "id": "did:web:buyer.example#decision-8842" },
"decisionType": "award",
"madeBy": { "scheme": "did", "id": "did:web:buyer.example#agent-eval-3" },
"underMandate": { "scheme": "did", "id": "did:web:buyer.example#mandate-eval-3" },
"inputs": [
{ "scheme": "did", "id": "did:web:buyer.example#submission-5521" },
{ "scheme": "did", "id": "did:web:buyer.example#submission-5522" }
],
"policiesApplied": [
{ "scheme": "did", "id": "did:web:buyer.example#policy-eval-mat" }
],
"rationale": "Most Advantageous Tender (price 0.2, quality 0.55, social 0.25). submission-5521 scored 0.859474, ahead of submission-5522 at 0.841500 (margin 0.017974). The dearer bid wins on materially higher quality, accepting a 5.56% price premium over the lower bid.",
"outcome": { "awardedSubmission": "did:web:buyer.example#submission-5521" },
"humanApproval": { "scheme": "did", "id": "did:web:buyer.example#approval-771" },
"provenance": {
"generatedBy": { "scheme": "did", "id": "did:web:buyer.example#agent-eval-3" },
"generatedAt": "2026-06-21T14:08:00Z",
"usedPolicies": [{ "scheme": "did", "id": "did:web:buyer.example#policy-eval-mat" }],
"signature": { "type": "Ed25519Signature2020", "value": "z58…" }
}
}
This single object records what was decided, which synthetic agent decided it, under which mandate, from which inputs, under which policy, with what rationale, with which human approval, and with cryptographic provenance — the accountability guarantee that distinguishes a SIGNET network from a conventional procurement platform.
Published under CC0 1.0. © 2026 Concert Foundation — to the extent any rights subsist, they are dedicated to the public domain. SIGNET and "SIGNET Certified" are marks administered by Concert Foundation under the IP & Licensing Policy.
Object reference
The core model, field by field
Generated from the JSON Schema. EN 16931 Business Term mappings appear on the invoicing objects. Extension and profile objects are specified in their own documents, indexed below; their schemas are in the download list.
Foundation layer
Identifier
A typed, scheme-qualified identifier.
| Field | Type | Card. | Definition |
|---|---|---|---|
scheme | string | 1 | Identifier scheme. See codelists/identifierScheme.csv. |
id | string | 1 | Identifier value within the scheme. |
uri | string | 0..1 | Resolvable URI for the identified entity, where one exists. |
Value
A monetary amount (EN 16931 aligned).
| Field | Type | Card. | Definition |
|---|---|---|---|
amount | number | 1 | Numeric amount. |
currency | string | 1 | ISO 4217 three-letter code. |
taxIncluded | boolean | 0..1 | Whether the amount is tax-inclusive. |
Period
A span of time.
| Field | Type | Card. | Definition |
|---|---|---|---|
startDate | string | 0..1 | Inclusive start. |
endDate | string | 0..1 | Inclusive end. |
durationInDays | integer | 0..1 | Convenience duration where dates are indicative. |
Classification
A coded classification against a controlled scheme.
| Field | Type | Card. | Definition |
|---|---|---|---|
scheme | string | 1 | Classification scheme. |
id | string | 1 | Code value. |
description | string | 0..1 | Human-readable label. |
Item
A line item.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | string | 1 | Item identifier, unique within its containing object. |
description | string | 1 | What the item is. |
classification | Classification | 0..1 | — |
additionalClassifications | Classification[] | 0..* | — |
quantity | number | 0..1 | Quantity. |
unitPrice | Value | 0..1 | Price per unit. |
Credential
Reference to a W3C Verifiable Credential asserting a claim about a Party.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | string | 1 | Credential identifier. |
type | string[] | 1..* | VC types. |
issuer | Identifier | 1 | Issuing authority. |
issuanceDate | string | 1 | — |
expirationDate | string | 0..1 | — |
credentialSubject | object | 1 | The claims, per the VC data model. |
proof | object | 1 | Cryptographic proof (may be a BBS selective-disclosure proof). |
selectiveDisclosure | boolean | 0..1 | Whether the credential supports zero-knowledge selective disclosure. |
Document
A reference to a document or attachment.
| Field | Type | Card. | Definition |
|---|---|---|---|
id | string | 1 | — |
documentType | string | 1 | Coded type. See codelists/documentType.csv. |
title | string | 0..1 | — |
url | string | 0..1 | — |
hash | string | 0..1 | Content hash for integrity. |
accessGrant | Identifier | 0..1 | Reference to a Consent object where access is controlled. |
Provenance
Who or what produced an assertion, when, and from what (W3C PROV aligned).
| Field | Type | Card. | Definition |
|---|---|---|---|
generatedBy | Identifier | 1 | The agent or activity that produced the assertion. |
generatedAt | string | 1 | — |
derivedFrom | Identifier[] | 0..* | — |
usedPolicies | Identifier[] | 0..* | — |
signature | object | 0..1 | Cryptographic signature over the assertion. |
Score
A per-criterion evaluation score.
| Field | Type | Card. | Definition |
|---|---|---|---|
criterion | string | 1 | The criterion scored. |
value | number | 1 | The score. |
weight | number | 0..1 | Criterion weight, where applicable. |
rationale | string | 0..1 | Why this score. |
Unit
Unit of measure and unit price.
| Field | Type | Card. | Definition |
|---|---|---|---|
code | string | 0..1 | UN/ECE Rec 20 unit-of-measure code (e.g. C62, DAY, MTR). |
name | string | 0..1 | — |
unitPrice | Value | 0..1 | — |
InvoiceLine
A single invoice line. Aligned to EN 16931 BG-25 (INVOICE LINE).
| Field | Type | Card. | Definition | EN 16931 |
|---|---|---|---|---|
id | string | 1 | Invoice line identifier. | BT-126 Invoice line identifier |
note | string | 0..1 | — | BT-127 Invoice line note |
quantity | number | 1 | — | BT-129 Invoiced quantity |
unitOfMeasure | string | 0..1 | — | BT-130 Invoiced quantity unit of measure code (UN/ECE Rec 20) |
itemName | string | 1 | — | BT-153 Item name |
itemNetPrice | Value | 0..1 | — | BT-146 Item net price |
netAmount | Value | 1 | — | BT-131 Invoice line net amount |
classification | Classification | 0..1 | — | BT-158 Item classification identifier |
vatCategoryCode | string | 0..1 | — | BT-151 Invoiced item VAT category code |
vatRate | number | 0..1 | — | BT-152 Invoiced item VAT rate |
VatBreakdown
A VAT category subtotal. Aligned to EN 16931 BG-23 (VAT BREAKDOWN).
Party
Any actor in the network. Subtyped by role.
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "Party" | 0..1 | — |
id | Identifier | 1 | — |
identifiers | Identifier[] | 0..* | — |
name | string | 1 | — |
roles | string[] | 1..* | — |
partyType | string organization · person · agent | 1 | — |
address | object | 0..1 | — |
contactPoint | object | 0..1 | — |
credentials | Credential[] | 0..* | — |
memberOf | Identifier | 0..1 | — |
Process layer
Need
The demand signal that initiates procurement (OCDS planning stage).
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "Need" | 0..1 | — |
id | Identifier | 1 | — |
title | string | 1 | — |
description | string | 0..1 | — |
requestingParty | Identifier | 1 | — |
budget | Value | 0..1 | — |
classification | Classification | 0..1 | — |
rationale | string | 0..1 | — |
governingPolicies | Identifier[] | 0..* | Policy references constraining this procurement. |
SourcingEvent
A request to the market: RFP, RFQ, ITT, tender, or call-off competition (OCDS tender stage).
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "SourcingEvent" | 0..1 | — |
id | Identifier | 1 | — |
title | string | 1 | — |
procuringParty | Identifier | 1 | — |
procedure | string | 1 | See codelists/procedure.csv. |
status | string planned · active · evaluating · complete · cancelled · withdrawn | 1 | — |
lots | object[] | 0..* | — |
items | Item[] | 0..* | — |
value | Value | 0..1 | — |
eligibilityCriteria | Identifier[] | 0..* | References to Policy objects. |
evaluationCriteria | Identifier[] | 0..* | References to Policy objects. |
period | Period | 0..1 | — |
documents | Document[] | 0..* | — |
Submission
A supplier's response to a SourcingEvent: bid, tender, quote, or proposal.
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "Submission" | 0..1 | — |
id | Identifier | 1 | — |
sourcingEvent | Identifier | 1 | — |
lot | string | 0..1 | — |
submittingParty | Identifier | 1 | — |
submittedBy | Identifier | 0..1 | — |
items | Item[] | 0..* | — |
value | Value | 0..1 | — |
disclosedCredentials | Credential[] | 0..* | — |
sealedProof | object | 0..1 | Encrypted submission + proof where sealed-bid cryptography applies. |
status | string draft · submitted · withdrawn · admissible · inadmissible | 1 | — |
Evaluation
The scoring of a submission against the evaluation criteria.
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "Evaluation" | 0..1 | — |
id | Identifier | 1 | — |
submission | Identifier | 1 | — |
criteria | Identifier | 1 | Reference to the Policy holding the evaluation model. |
scores | Score[] | 1..* | — |
evaluatedBy | Identifier | 1 | The agent (human or synthetic) performing the evaluation. |
result | string passed · failed · ranked | 1 | — |
decision | Identifier | 0..1 | Link to the Decision record. |
Award
The decision to award (OCDS award stage).
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "Award" | 0..1 | — |
id | Identifier | 1 | — |
sourcingEvent | Identifier | 1 | — |
awardedParty | Identifier | 1 | — |
value | Value | 1 | — |
rationale | string | 0..1 | — |
decision | Identifier | 1 | The Decision record supporting the award. |
standstillPeriod | Period | 0..1 | Where regulation requires a standstill (e.g. UK Procurement Act). |
Contract
The binding agreement (OCDS contract stage).
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "Contract" | 0..1 | — |
id | Identifier | 1 | — |
award | Identifier | 0..1 | The award it derives from. |
parties | Identifier[] | 1..* | — |
title | string | 1 | — |
value | Value | 1 | — |
period | Period | 1 | — |
obligations | obligation[] | 0..* | — |
documents | Document[] | 0..* | — |
governingPolicies | Identifier[] | 0..* | — |
Order
A call-off or purchase order against a contract or catalogue (UBL Order aligned).
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "Order" | 0..1 | — |
id | Identifier | 1 | — |
contract | Identifier | 0..1 | The contract drawn against. |
buyer | Identifier | 1 | — |
seller | Identifier | 1 | — |
items | Item[] | 1..* | — |
value | Value | 1 | — |
deliveryPeriod | Period | 0..1 | — |
Catalogue
A structured offering of goods/services (UBL Catalogue / Peppol BIS Catalogue aligned).
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "Catalogue" | 0..1 | — |
id | Identifier | 1 | — |
providerParty | Identifier | 1 | — |
items | Item[] | 1..* | — |
validityPeriod | Period | 0..1 | — |
Obligation
A contractual obligation, deliverable, or milestone with a compliance state.
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "Obligation" | 0..1 | — |
id | string | 1 | — |
description | string | 1 | — |
dueDate | string | 0..1 | — |
responsibleParty | Identifier | 0..1 | — |
status | string pending · met · breached · waived | 1 | — |
evidence | Document[] | 0..* | — |
dischargedBy | Identifier[] | 0..* | The Order, Invoice, or Document(s) that discharged this obligation. SHOULD be present once status is `met`. |
Invoice
An invoice, fully aligned to EN 16931 so it is convertible to Peppol BIS Billing / UBL Invoice / Factur-X. This alignment is what makes a SIGNET network natively compliant with the EU ViDA cross-border e-invoicing mandate.
| Field | Type | Card. | Definition | EN 16931 |
|---|---|---|---|---|
type | "Invoice" | 0..1 | — | — |
id | Identifier | 1 | — | BT-1 Invoice number |
invoiceTypeCode | string | 0..1 | — | BT-3 Invoice type code (e.g. 380 commercial invoice) |
issueDate | string | 1 | — | BT-2 Invoice issue date |
currency | string | 1 | — | BT-5 Invoice currency code (ISO 4217) |
contract | Identifier | 0..1 | — | BT-12 Contract reference |
order | Identifier | 0..1 | — | BT-13 Purchase order reference |
settles | Identifier[] | 0..* | SIGNET-original (not an EN 16931 BT). The Obligation(s) this invoice settles. Omitted on Peppol BIS projection. | — |
seller | Identifier | 1 | — | BG-4 SELLER (BT-27 seller name resolved via Party) |
buyer | Identifier | 1 | — | BG-7 BUYER (BT-44 buyer name resolved via Party) |
lines | InvoiceLine[] | 1..* | — | BG-25 INVOICE LINE |
vatBreakdown | VatBreakdown[] | 0..* | — | BG-23 VAT BREAKDOWN |
lineExtensionTotal | Value | 0..1 | — | BT-106 Sum of invoice line net amount |
taxExclusiveTotal | Value | 0..1 | — | BT-109 Invoice total amount without VAT |
taxTotal | Value | 1 | — | BT-110 Invoice total VAT amount |
taxInclusiveTotal | Value | 0..1 | — | BT-112 Invoice total amount with VAT |
payableAmount | Value | 1 | — | BT-115 Amount due for payment |
paymentDueDate | string | 0..1 | — | BT-9 Payment due date |
paymentTerms | string | 0..1 | — | BT-20 Payment terms |
Agent layer
SyntheticAgent
An AI agent operating in the network as a first-class Party.
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "SyntheticAgent" | 0..1 | — |
id | Identifier | 1 | — |
name | string | 1 | — |
operatedBy | Identifier | 1 | — |
model | string | 0..1 | Underlying model family (provenance only; SIGNET is model-agnostic). |
capabilities | object[] | 1..* | — |
mandate | Identifier | 1 | — |
agentCard | string | 0..1 | A2A Agent Card location. |
Mandate
The authority granted to an agent: what it may do, within what limits.
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "Mandate" | 0..1 | — |
id | Identifier | 1 | — |
agent | Identifier | 1 | — |
grantedBy | Identifier | 1 | — |
permittedCapabilities | string[] | 1..* | — |
constraints | Identifier[] | 0..* | Policy references: hard limits. |
approvalThresholds | Identifier[] | 0..* | Policy references: human-in-the-loop conditions. |
scope | object | 1 | Data and entity scope (sandbox boundary). |
validity | Period | 0..1 | — |
Decision
A decision taken in the network, by a human or synthetic agent, with inputs and rationale.
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "Decision" | 0..1 | — |
id | Identifier | 1 | — |
decisionType | string | 1 | See codelists/decisionType.csv. |
madeBy | Identifier | 1 | — |
underMandate | Identifier | 0..1 | — |
inputs | Identifier[] | 0..* | — |
policiesApplied | Identifier[] | 0..* | — |
rationale | string | 1 | Human-readable rationale. MANDATORY. |
outcome | object | 1 | The decision outcome. |
humanApproval | Identifier | 0..1 | — |
provenance | Provenance | 1 | — |
Policy
A machine-readable, human-auditable rule. Rules-as-code.
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "Policy" | 0..1 | — |
id | Identifier | 1 | — |
policyType | string eligibility · evaluation · approval · constraint · compliance | 1 | — |
expressionLanguage | string | 1 | e.g. rego, dmn, cel. |
expression | string | 1 | The executable rule. |
humanReadable | string | 1 | Plain-language statement of the same rule. MANDATORY. |
version | string | 1 | — |
issuedBy | Identifier | 1 | — |
Trust layer
Event
An append-only record of a material change. Tamper-evident via hash chaining.
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "Event" | 0..1 | — |
id | Identifier | 1 | — |
eventType | string | 1 | See codelists/eventType.csv (open). |
subject | Identifier | 1 | — |
actor | Identifier | 1 | — |
timestamp | string | 1 | — |
payload | object | 0..1 | — |
previousEventHash | string | 0..1 | Hash of the prior event, forming a tamper-evident chain. |
provenance | Provenance | 1 | — |
Consent
A data-sovereignty access grant (Solid pattern expressed as CDM data).
| Field | Type | Card. | Definition |
|---|---|---|---|
type | "Consent" | 0..1 | — |
id | Identifier | 1 | — |
grantor | Identifier | 1 | — |
grantee | Identifier | 1 | — |
resource | Identifier[] | 1..* | — |
purpose | string | 1 | A human-readable statement of the purpose for which access is granted, not a machine-evaluable term. The string interoperates; its evaluation is not defined by this standard. A profile MAY define a purposeCode extension with a codelist appropriate to its jurisdiction or sector. |
validity | Period | 1 | — |
revocable | boolean | 1 | Whether the grant may be withdrawn before expiry. This is a capability flag, not a status: withdrawal is recorded by appending a consent.revoked Event, never by mutating this object (specification §7.4). |
proof | object | 0..1 | — |
Codelists
Controlled vocabularies
Closed lists are normative; open lists are extensible.
partyRoleClosed| Code | Title | Description |
|---|---|---|
buyer | Buyer | The party acquiring goods/services. |
supplier | Supplier | The party offering goods/services. |
procuringEntity | Procuring entity | The entity running the procurement on behalf of the buyer. |
payer | Payer | The party making payment. |
payee | Payee | The party receiving payment. |
humanAgent | Human agent | A natural person acting in the network. |
syntheticAgent | Synthetic agent | An AI agent acting in the network. |
certifier | Certifier | An authority issuing verifiable credentials. |
observer | Observer | A read-only participant (auditor, regulator). |
procedureClosed| Code | Title | Description |
|---|---|---|
open | Open | Any interested supplier may submit. |
restricted | Restricted | Two-stage: select then invite. |
competitiveFlexible | Competitive flexible procedure | Bespoke multi-stage procedure (UK Procurement Act 2023). |
directAward | Direct award | Award without competition where permitted. |
frameworkCallOff | Framework call-off | Call-off competition under an existing framework. |
policyTypeClosed| Code | Title | Description |
|---|---|---|
eligibility | Eligibility | Entry criteria for participation. |
evaluation | Evaluation | Scoring model for submissions. |
approval | Approval | Approval routing and thresholds. |
constraint | Constraint | Hard limits on agent behaviour. |
compliance | Compliance | Regulatory or policy compliance rules. |
submissionStatusClosed| Code | Title | Description |
|---|---|---|
draft | Draft | Not yet submitted. |
submitted | Submitted | Lodged with the procuring entity. |
withdrawn | Withdrawn | Withdrawn by the supplier. |
admissible | Admissible | Passed admissibility checks. |
inadmissible | Inadmissible | Failed admissibility checks. |
decisionTypeClosed| Code | Title | Description |
|---|---|---|
admissibility | Admissibility | Whether a submission is admissible. |
evaluation | Evaluation | Scoring of a submission. |
award | Award | Decision to award. |
negotiationMove | Negotiation move | A move within a negotiation. |
qualification | Qualification | Decision to qualify a supplier (onboarding). |
identifierSchemeClosed| Code | Title | Description |
|---|---|---|
did | Decentralised Identifier | W3C DID. RECOMMENDED for parties and agents. |
gleif:lei | Legal Entity Identifier | ISO 17442 LEI issued under GLEIF. |
gs1:gln | Global Location Number | GS1 GLN. |
vat | VAT number | National VAT registration number. |
companies-house | UK Companies House number | UK company registration number. |
peppol | PEPPOL Participant Identifier | Peppol network participant id. |
invoiceTypeCodeClosed| Code | Title | Description |
|---|---|---|
380 | Commercial invoice | Standard commercial invoice (EN 16931 BT-3 default). |
381 | Credit note | Document cancelling all or part of an invoice. |
384 | Corrected invoice | Invoice correcting a previously issued invoice. |
389 | Self-billed invoice | Invoice raised by the buyer on behalf of the supplier. |
326 | Partial invoice | Invoice for part of a delivery or contract. |
vatCategoryClosed| Code | Title | Description |
|---|---|---|
S | Standard rate | Standard VAT rate applies (EN 16931 BT-151/BT-118). |
Z | Zero rated | Goods/services taxed at zero rate. |
E | Exempt | Exempt from VAT. |
AE | Reverse charge | VAT reverse charge applies (buyer accounts for VAT). |
G | Export outside EU | Free export item, VAT not charged. |
K | Intra-community supply | Zero-rated intra-community supply of goods/services. |
O | Outside scope | Services outside the scope of VAT. |
eventTypeOpen| Code | Title | Description |
|---|---|---|
need.raised | Need raised | A procurement need was raised. |
sourcingEvent.published | Sourcing event published | A sourcing event was published to the market. |
submission.lodged | Submission lodged | A supplier lodged a submission. |
evaluation.completed | Evaluation completed | A submission was evaluated. |
award.decided | Award decided | An award decision was taken. |
contract.signed | Contract signed | A contract was executed. |
mandate.refused | Mandate refused | An agent action was refused because it fell outside the mandate relied on. |
obligation.discharged | Obligation discharged | An obligation reached `met`, discharged by a settling artefact (Order/Invoice/Document). |
bid.placed | Bid placed | A bid was placed or revised in an Auction; the ordered bid.placed stream is the hash-chained auction record. |
sourcingEvent.planned | Sourcing event planned | A sourcing event was created in the planning stage. |
sourcingEvent.closed | Sourcing event closed | The submission window closed and evaluation began. |
sourcingEvent.completed | Sourcing event completed | A sourcing event reached its intended end. |
sourcingEvent.cancelled | Sourcing event cancelled | A sourcing event was cancelled before completion. |
sourcingEvent.withdrawn | Sourcing event withdrawn | A sourcing event was withdrawn by the procuring party. |
submission.created | Submission created | A submission was created in draft. |
submission.admitted | Submission admitted | A submission was ruled admissible by an admissibility Decision. |
submission.excluded | Submission excluded | A submission was ruled inadmissible by an admissibility Decision. |
submission.withdrawn | Submission withdrawn | A submission was withdrawn by the supplier. |
obligation.created | Obligation created | An obligation was created pending fulfilment. |
obligation.breached | Obligation breached | An obligation was not fulfilled as required. |
obligation.waived | Obligation waived | An obligation was waived by the party entitled to enforce it. |
auction.scheduled | Auction scheduled | An auction was created and scheduled. |
auction.opened | Auction opened | An auction opened for participation. |
auction.started | Auction started | Bidding began. |
auction.closed | Auction closed | An auction closed under its deterministic rules. |
auction.cancelled | Auction cancelled | An auction was cancelled before close. |
bid.withdrawn | Bid withdrawn | A bid was withdrawn by the bidder. |
bid.won | Bid won | A bid was determined the winning bid at close. |
bid.rejected | Bid rejected | A bid was rejected as invalid. |
bid.superseded | Bid superseded | A standing bid was superseded by a later bid from the same bidder; the payload carries supersededBy. |
eventTypeCoreClosed| Code | Title | Description |
|---|---|---|
consent.granted | Consent granted | A data-sovereignty access grant was issued. |
consent.revoked | Consent revoked | An access grant was withdrawn before expiry. |
mandate.granted | Mandate granted | Delegated authority was conferred on an agent. |
mandate.revoked | Mandate revoked | Delegated authority was withdrawn before expiry. |
documentTypeOpen| Code | Title | Description |
|---|---|---|
tenderNotice | Tender notice | Notice advertising a sourcing event. |
evaluationCriteria | Evaluation criteria | The published evaluation model. |
specification | Specification | Technical or service specification. |
signedContract | Signed contract | The executed contract document. |
evidence | Evidence | Evidence of obligation fulfilment. |
Examples
Worked instances
{
"@context": "https://concert.foundation/signet/v0.1/context.jsonld",
"type": "Invoice",
"id": {
"scheme": "peppol",
"id": "INV-2026-000512"
},
"invoiceTypeCode": "380",
"issueDate": "2026-10-05T00:00:00Z",
"currency": "EUR",
"contract": {
"scheme": "did",
"id": "did:web:buyer.example#contract-3310"
},
"order": {
"scheme": "did",
"id": "did:web:buyer.example#order-7781"
},
"settles": [
{
"scheme": "did",
"id": "did:web:buyer.example#contract-3310/ob-1"
}
],
"seller": {
"scheme": "gleif:lei",
"id": "5299000ACME00NETWRK1"
},
"buyer": {
"scheme": "gleif:lei",
"id": "5299000BUYER00000001"
},
"lines": [
{
"id": "1",
"itemName": "Core router managed service — monthly",
"quantity": 100,
"unitOfMeasure": "MON",
"itemNetPrice": {
"amount": 50,
"currency": "EUR"
},
"netAmount": {
"amount": 5000,
"currency": "EUR"
},
"classification": {
"scheme": "cpv",
"id": "72720000"
},
"vatCategoryCode": "S",
"vatRate": 21
},
{
"id": "2",
"itemName": "Field engineering — day rate",
"quantity": 10,
"unitOfMeasure": "DAY",
"itemNetPrice": {
"amount": 120,
"currency": "EUR"
},
"netAmount": {
"amount": 1200,
"currency": "EUR"
},
"vatCategoryCode": "S",
"vatRate": 21
}
],
"vatBreakdown": [
{
"taxableAmount": {
"amount": 6200,
"currency": "EUR"
},
"taxAmount": {
"amount": 1302,
"currency": "EUR"
},
"categoryCode": "S",
"rate": 21
}
],
"lineExtensionTotal": {
"amount": 6200,
"currency": "EUR"
},
"taxExclusiveTotal": {
"amount": 6200,
"currency": "EUR"
},
"taxTotal": {
"amount": 1302,
"currency": "EUR"
},
"taxInclusiveTotal": {
"amount": 7502,
"currency": "EUR"
},
"payableAmount": {
"amount": 7502,
"currency": "EUR"
},
"paymentDueDate": "2026-11-04T00:00:00Z",
"paymentTerms": "Net 30 days from invoice date."
}{
"@context": "https://concert.foundation/signet/v0.1/context.jsonld",
"type": "SourcingEvent",
"id": {
"scheme": "did",
"id": "did:web:buyer.example#event-1207"
},
"title": "Network managed services — Northern region",
"procuringParty": {
"scheme": "did",
"id": "did:web:buyer.example#buyer"
},
"procedure": "competitiveFlexible",
"status": "active",
"lots": [
{
"id": "lot-1",
"title": "Core transport",
"value": {
"amount": 12000000,
"currency": "EUR"
}
}
],
"value": {
"amount": 12000000,
"currency": "EUR"
},
"eligibilityCriteria": [
{
"scheme": "did",
"id": "did:web:buyer.example#policy-elig-iso27001"
}
],
"evaluationCriteria": [
{
"scheme": "did",
"id": "did:web:buyer.example#policy-eval-mat"
}
],
"period": {
"startDate": "2026-07-01T00:00:00Z",
"endDate": "2026-08-15T17:00:00Z"
}
}{
"@context": "https://concert.foundation/signet/v0.1/context.jsonld",
"type": "Decision",
"id": { "scheme": "did", "id": "did:web:buyer.example#decision-8842" },
"decisionType": "award",
"madeBy": { "scheme": "did", "id": "did:web:buyer.example#agent-eval-3" },
"underMandate": { "scheme": "did", "id": "did:web:buyer.example#mandate-eval-3" },
"inputs": [
{ "scheme": "did", "id": "did:web:buyer.example#submission-5521" },
{ "scheme": "did", "id": "did:web:buyer.example#submission-5522" }
],
"policiesApplied": [ { "scheme": "did", "id": "did:web:buyer.example#policy-eval-mat" } ],
"rationale": "Most Advantageous Tender (price 0.2, quality 0.55, social 0.25). submission-5521 scored 0.859474, ahead of submission-5522 at 0.841500 (margin 0.017974). The dearer bid wins on materially higher quality, accepting a 5.56% price premium over the lower bid.",
"outcome": {
"awardedSubmission": "did:web:buyer.example#submission-5521",
"ranking": [
{ "submission": "did:web:buyer.example#submission-5521", "total": 0.859474 },
{ "submission": "did:web:buyer.example#submission-5522", "total": 0.8415 }
]
},
"humanApproval": { "scheme": "did", "id": "did:web:buyer.example#approval-771" },
"provenance": {
"generatedBy": { "scheme": "did", "id": "did:web:buyer.example#agent-eval-3" },
"generatedAt": "2026-06-21T14:08:00Z",
"derivedFrom": [
{ "scheme": "did", "id": "did:web:buyer.example#submission-5521" },
{ "scheme": "did", "id": "did:web:buyer.example#submission-5522" }
],
"usedPolicies": [ { "scheme": "did", "id": "did:web:buyer.example#policy-eval-mat" } ],
"signature": { "type": "Ed25519Signature2020", "value": "z58…" }
}
}{
"@context": "https://concert.foundation/signet/v0.1/context.jsonld",
"type": "Need",
"id": {
"scheme": "did",
"id": "did:web:buyer.example#need-0420"
},
"title": "Managed network services — Northern region refresh",
"requestingParty": {
"scheme": "did",
"id": "did:web:buyer.example#buyer"
},
"budget": {
"amount": 12000000,
"currency": "EUR"
},
"classification": {
"scheme": "cpv",
"id": "72720000",
"description": "Wide area network services"
},
"rationale": "End-of-life transport equipment refresh across the northern operating region.",
"governingPolicies": [
{
"scheme": "did",
"id": "did:web:buyer.example#policy-elig-iso27001"
}
]
}{
"@context": "https://concert.foundation/signet/v0.1/context.jsonld",
"type": "Contract",
"id": {
"scheme": "did",
"id": "did:web:buyer.example#contract-3310"
},
"award": {
"scheme": "did",
"id": "did:web:buyer.example#award-2208"
},
"parties": [
{
"scheme": "did",
"id": "did:web:buyer.example#buyer"
},
{
"scheme": "did",
"id": "did:web:acme-networks.example#acme"
}
],
"title": "Managed network services — Northern region",
"value": {
"amount": 12000000,
"currency": "EUR"
},
"period": {
"startDate": "2026-09-01T00:00:00Z",
"endDate": "2029-08-31T23:59:59Z"
},
"obligations": [
{
"type": "Obligation",
"id": "ob-1",
"description": "Achieve 99.95% core availability each calendar month.",
"status": "met",
"dischargedBy": [
{
"scheme": "peppol",
"id": "INV-2026-000512"
}
]
},
{
"type": "Obligation",
"id": "ob-2",
"description": "Complete northern transport migration by 2027-06-30.",
"dueDate": "2027-06-30T00:00:00Z",
"status": "pending"
}
]
}{
"@context": "https://concert.foundation/signet/v0.1/context.jsonld",
"type": "Policy",
"id": {
"scheme": "did",
"id": "did:web:buyer.example#policy-eval-mat"
},
"policyType": "evaluation",
"expressionLanguage": "rego",
"expression": "package signet.eval\nscore := price*0.2 + quality*0.55 + social*0.25",
"humanReadable": "Most Advantageous Tender: price 20%, quality 55%, social value 25%.",
"version": "1.1.0",
"issuedBy": {
"scheme": "did",
"id": "did:web:buyer.example#buyer"
}
}Extensions & profiles
The core stays lean; domains extend it
Domain structure is added through extensions and profiles that add object types, fields, or codelist values and never redefine core fields — the OCDS extension pattern. This index is maintained in the standard's repository.
onboardingSchemas + demo shipped (in-tree, core v0.1); conformance rules ship (conformance/rules/check-onboarding.js)
OnboardingCase, SupplierQualification (durable status with first-class conditional qualification, value caps, category restrictions); credentialType codelist
auctionSchemas + demo shipped (in-tree, core v0.1); conformance rules ship (conformance/rules/check-auction.js)
Auction, Bid (a profile of the sourcing flow — reverse / english / dutch / sealed-bid / multi-criteria; deterministic, operator-independent close); auctionType codelist
identityWorking Draft — schema + worked example shipped; demo emits Approval; conformance rules ship (conformance/rules/check-identity.js)
Approval (verifiable human approval); delegationOfAuthority credential type; normative no-PII rule for hash-anchored records
commodity-riskSpec + schemas + conformance rules shipped — six schemas, ten codelists, an eleven-file full-loop example, and the six rules as an executable checker (conformance/rules/check-commodity-risk.js); separately-namespaced
Portfolio-level commodity risk governance (positions, coverage corridors as Policy subtypes, price marks, assessments, price-shock scenarios, hedge proposals bridging to core Need)
receiptWorking Draft (spec only; schemas to follow)
Receipt, MatchResult — receipt/acceptance and the governed three-way match (tolerances as a matchTolerance Policy; the match is a mandate-bound Decision)
performanceWorking Draft (spec only; schemas to follow)
ServiceLevelPolicy, PerformanceAssessment — SLAs/KPIs as Policy and derived, event-anchored supplier performance assessments that feed the qualification lifecycle
amendmentsWorking Draft (spec only; schemas to follow)
Amendment — event-anchored contract deltas (variation / extension / renewal / novation / termination) with derived current state
frameworksWorking Draft (spec only; schemas to follow)
FrameworkAgreement (Contract subtype), CallOff (direct award / mini-competition) with a conformance-checkable drawdown invariant (Σ call-offs ≤ ceiling)
negotiationWorking Draft (spec only; schemas to follow)
Negotiation, Offer — a governed exchange of offers over named terms under per-term Mandates; the object model behind the existing decisionType: negotiationMove
requirementsWorking Draft (spec; schemas to follow)
Requirement, RequirementSet — what was asked, as a versioned addressable object; selection-is-derivation, variance as a Decision-backed relation; relies on three core sockets (Score.criterionRef, Obligation.provenance, Submission.responses)
auction-platformWorking Draft
Certification profile for eAuction platforms — the first product-certification path; composes the auction + identity extensions and the public conformance suite into five demonstrable requirements (valid objects · deterministic close · tamper-evident record · governed awards · no PII in the chain)
The full index — its status vocabulary, the governance notes, and the in-tree versus separately-namespaced rule — is maintained at docs/extensions/README.md at v0.17.1.
Private fields
Carrying local structure without leaving the standard
A published extension is not the only way to add structure. An implementer can carry a private local field - an ERP company code, a cost centre, an internal approval reference - on a core object, without failing document conformance and without publishing anything.
- The mechanism
- Object schemas admit any property matching
^[a-z][a-z0-9-]*:[A-Za-z][A-Za-z0-9]*$— a prefix, a colon, a field name — alongside an unchangedadditionalProperties: false. It is present at 22 sites across the published schemas. Soexample-org:costCentrevalidates, while a misspelled core field carries no prefix and is still refused. That refusal is the property the wire contract rests on, and it is untouched. - What a prefixed field is not
- Permitted by the core schema and constrained by nothing else. It is not modelled, not assessed by core conformance, earns no mark, and is never promoted into the core model without first becoming a published extension.
- Reserved and forbidden prefixes
signet:andconcert:are reserved to Concert, and barex-is forbidden. These are enforced by the conformance suite rather than by the schema pattern: a negative-lookahead regex works under one validator but sits outside the portable subset others implement, and a governance rule encoded there would be silently unenforced on exactly the implementations least likely to be checked. Prefixes are otherwise self-asserted and first-come — Concert operates no prefix registry.- JSON-LD corollary
- A private prefixed field has no context mapping, so it is dropped during JSON-LD expansion. That is semantically correct — a private field has no global meaning — and it is a forcing function: to survive expansion you must publish a context, which is the first step toward being an extension rather than a private field.
- Proven, not asserted
party-reserved-prefix.jsonsignet: is a reserved prefix — admitted by the schema, refused by the suiterejected by the suiteorder-private-extension.jsona private prefixed field is carried without failing document conformancevalidatesparty-unknown-property.jsonan unprefixed unknown property is still refused — the wire contract is untouchedrejected
Machine-readable source
Download the artifacts
definitions.schema.jsonhttps://concert.foundation/signet/v0.1/definitions.schema.jsonparty.schema.jsonhttps://concert.foundation/signet/v0.1/party.schema.jsonneed.schema.jsonhttps://concert.foundation/signet/v0.1/need.schema.jsonsourcing-event.schema.jsonhttps://concert.foundation/signet/v0.1/sourcing-event.schema.jsonsubmission.schema.jsonhttps://concert.foundation/signet/v0.1/submission.schema.jsonevaluation.schema.jsonhttps://concert.foundation/signet/v0.1/evaluation.schema.jsonaward.schema.jsonhttps://concert.foundation/signet/v0.1/award.schema.jsoncontract.schema.jsonhttps://concert.foundation/signet/v0.1/contract.schema.jsonorder.schema.jsonhttps://concert.foundation/signet/v0.1/order.schema.jsoncatalogue.schema.jsonhttps://concert.foundation/signet/v0.1/catalogue.schema.jsonobligation.schema.jsonhttps://concert.foundation/signet/v0.1/obligation.schema.jsoninvoice.schema.jsonhttps://concert.foundation/signet/v0.1/invoice.schema.jsonsynthetic-agent.schema.jsonhttps://concert.foundation/signet/v0.1/synthetic-agent.schema.jsonmandate.schema.jsonhttps://concert.foundation/signet/v0.1/mandate.schema.jsondecision.schema.jsonhttps://concert.foundation/signet/v0.1/decision.schema.jsonpolicy.schema.jsonhttps://concert.foundation/signet/v0.1/policy.schema.jsonevent.schema.jsonhttps://concert.foundation/signet/v0.1/event.schema.jsonconsent.schema.jsonhttps://concert.foundation/signet/v0.1/consent.schema.jsoncontext.jsonldhttps://concert.foundation/signet/v0.1/context.jsonldauction.schema.jsonhttps://concert.foundation/signet/v0.1/auction.schema.jsonbid.schema.jsonhttps://concert.foundation/signet/v0.1/bid.schema.jsononboarding-case.schema.jsonhttps://concert.foundation/signet/v0.1/onboarding-case.schema.jsonsupplier-qualification.schema.jsonhttps://concert.foundation/signet/v0.1/supplier-qualification.schema.jsonapproval.schema.jsonhttps://concert.foundation/signet/v0.1/approval.schema.jsonexposure-position.schema.jsonhttps://concert.foundation/signet/v0.1/exposure-position.schema.jsoncoverage-policy.schema.jsonhttps://concert.foundation/signet/v0.1/coverage-policy.schema.jsoncoverage-assessment.schema.jsonhttps://concert.foundation/signet/v0.1/coverage-assessment.schema.jsonprice-mark.schema.jsonhttps://concert.foundation/signet/v0.1/price-mark.schema.jsonscenario.schema.jsonhttps://concert.foundation/signet/v0.1/scenario.schema.jsonhedge-proposal.schema.jsonhttps://concert.foundation/signet/v0.1/hedge-proposal.schema.jsonpartyRole.csvhttps://concert.foundation/signet/v0.1/codelists/partyRole.csvprocedure.csvhttps://concert.foundation/signet/v0.1/codelists/procedure.csvpolicyType.csvhttps://concert.foundation/signet/v0.1/codelists/policyType.csvsubmissionStatus.csvhttps://concert.foundation/signet/v0.1/codelists/submissionStatus.csvdecisionType.csvhttps://concert.foundation/signet/v0.1/codelists/decisionType.csvidentifierScheme.csvhttps://concert.foundation/signet/v0.1/codelists/identifierScheme.csvinvoiceTypeCode.csvhttps://concert.foundation/signet/v0.1/codelists/invoiceTypeCode.csvvatCategory.csvhttps://concert.foundation/signet/v0.1/codelists/vatCategory.csveventType.csvhttps://concert.foundation/signet/v0.1/codelists/eventType.csveventTypeCore.csvhttps://concert.foundation/signet/v0.1/codelists/eventTypeCore.csvdocumentType.csvhttps://concert.foundation/signet/v0.1/codelists/documentType.csvHow the standard evolves
Changelog
Added
docs/positions/onenda-and-signet.md— a positioning paper on adopting oneNDA as the NDA step in sourcing. Non-normative and a proposal only: it states in its own summary that SIGNET does not currently model an NDA, and its front matter carries the claim triad (modelled: none,tested: none,certified: none) as data rather than prose. No schema, closed codelist, event code or governance register changes, and no change proposal is registered by it.public-interface.jsondeclares the file as consumed by the site build.
Changed
check-naming.jsadmits addresses on the domains reserved by RFC 2606 and RFC 6761.allowEmailsentries now take*, and the reserved domains are listed in the manifest as data. The rule failed on a worked example showing the shape of a notice address; an address on a reserved domain resolves to no one, so it discloses no person. This is a widening of the rule and is recorded as one — any address the patterns admit stops being a failure. Every other address still fails.
Fixed
check-release-version.js(npm run conformance:release-version), invalidate.yml: the version inpackage.jsonandpackage-lock.jsonmust equal the newest released heading in this file. The v0.17.1 tag was first cut with a[0.17.1]heading and0.17.0inpackage.json, because the release step cut a tag without the release commit every previous release had made. Nothing in this repository noticed, and the failure surfaced two repositories downstream in the website's build gate. A standard that depends on a consumer to detect its own release inconsistency has the control in the wrong repository — the D-19 shape, recorded again. The tag was re-cut on the corrected commit; nothing consumed the first cut, which existed for minutes and was never pinned by the site.CITATION.cffnamed version 0.3.0 with a release date of 2026-06-22. It was added once and never touched again, so a citation of this standard has named a version this repository never released since around v0.4.0 — the same fault as the tag, undetected across roughly fourteen releases because nothing downstream reads the file. Corrected to 0.17.1 / 2026-09-12, andcheck-release-version.jsnow covers it: the files a release must keep in step are the ones that name a version, not the ones a build happens to consume.cff-versionis the CFF schema version and is deliberately not checked.
Governance
- Defect register: D-45..D-52 recorded against the
commodity-riskextension (spec/tree divergences: core linkage, event types,policyEvaluationStatusbinding,Policysubtype,HedgeProposallifecycle) and the core primitives it leans on (unit of measure, delivery period, market identifiers). Facts only; no artifact changed. - Interests register: entry 4 (steward's origination of the
commodity-riskextension and of its remedies). - Registered under IAR-0006:
CP-Commodity-Risk-Linkage,CP-Quantity-Unit,CP-Market-Identifiers— defect-remedying (D-45..D-52). Adoption parked; comment periods run from ready-for-review. governance/EAE-0001.md— the first external analyst enquiry, received 9 September 2026 and decomposed into six dispositions. Role-based throughout; the originator is a Standards Committee candidate, so the verbatim comments are retained off-tree and the recusal consequence is recorded at intake. The record decides nothing.- Defect register: D-58..D-61 recorded, all from EAE-0001 —
SourcingEventhas no held state; reissuance has no lineage field;procedure.csvconflates legal procedure with event kind and is framed on one statute;Evaluationadmits one evaluator andScore'sadditionalProperties: falseforecloses a per-criterion one. Facts only; no artifact changed. - Registered under IAR-0006:
CP-Qualification-Lifecycle— defect-remedying (D-57 on its second surface,SupplierQualification). Three gates open; no shape proposed. Adoption parked; comment period runs from ready-for-review. - SE-0002 filed through the scope-enquiry route as issue #62 — what
Contractdenotes in v1, and whether organisational units are in scope. Two registered questions, no proposal. Same route SE-0001 took (#49); the mapping from SE number to issue is recorded here because the records cross-referenceSE-0002by name. - Evidence appended from EAE-0001, no existing text edited:
CP-Extension-Compositiongains §10 Evidence (an independent practitioner statement of the adoption risk the proposal exists to manage);governance/defects.mdgains an evidence section carrying the D-39 append and the D-57 second-surface cross-reference, so no defect row is edited. - Published
governance/RESPONSE-2026-08-implementer-enquiry.md, the response the v0.16.0 entry cited eleven days before it existed (D-40, closed). Drafted against v0.15.0 on 20 August; published against v0.16.1 stating per correction what has landed and what rides IAR-0003 (#43). The enquiry is published de-named; verbatim publication is forbidden by the naming rule. Comment period fourteen days from publication, not waived.
Added
- Adopter register.
registry/adopters.json(opens empty),registry/adopter-entry.schema.json,registry/founding-window.jsonandtools/check-adopters.js(npm run registry:adopters). An entry is a self-declared statement of practice (accepts,emits,internal-model) by an organisation, never a conformance claim: the schema admits no claim field or free text, and the checker bans claim words in keys and values independently of the schema. The checker also enforces uniqueness, date order, the published CDM namespace version (read from the definitions schema$id) and the founding window.CONTRIBUTING.mdgains "Declaring adoption"; the PR template gains an adopter-entry checklist;public-interface.jsondeclares both register files as consumed by the site build. Non-normative. governance/IAR-0007-founding-adopter-window.md— interim resolution establishing the register and a founding-adopter window that closes on constitution of the Standards Committee or at 23:59 UTC 31 December 2026, whichever is earlier. Founding status is a fact about timing and confers nothing. Nine declined alternatives recorded, including alignment to IAR-0006's expiry. Tier 1.
Fixed
check-state-model.jsgains C11 (terminal reachability), C12 (registry completeness), C13 (authority evidence) and C14 (basis scope). The v0.16.0 entry describing C11 and the D-15/D-16 closures citing C12 and C14 were premature: the registry changes had landed, the checks had not. Recorded as D-53.
Added — a registration window, two registered proposals, and the constitution drafts
governance/IAR-0006-registration-window.md reopens registration only, for change proposals
that remedy a recorded defect or resolve a timing dependency in a change already in flight.
Adoption stays parked and the harm carve-out is untouched. The window expires automatically on
constitution of the Standards Committee or at 23:59 UTC 30 September 2026, whichever is earlier,
and the record states the new facts that justify revisiting the 20 August standing rule nine days
after its adoption, rather than editing the rule away.
Registered under the window, each carrying the required banner, a role-based origin statement and
the steward's recusal: governance/proposals/CP-Requirement-Sockets.md — the remedy for D-34,
D-35 and D-36 as three additive, target-neutral core sockets — and
governance/proposals/CP-Extension-Composition-Amendment-A.md — published-extension fields ride
the landed Part 1 pattern with resolution by path, so Part 2 keeps the 2020-12 migration for its
remaining merit ($ref siblings) and drops unevaluatedProperties. Registration is not
adoption; both wait for the Committee, with their comment periods running meanwhile.
Drafted and deciding nothing until executed at the first session:
governance/CONSTITUTION-2026-09.md — appointments void without a completed assessment; quorum
is both members; adoption is by unanimity; the steward does not vote; deadlock leaves a proposal
Draft with the disagreement recorded; a recused matter falls to the remaining member; the change
of constitution trigger is minuted as a decision, not drifted past — with
governance/interests-register.md (initiates at execution; the steward's dual role and the
SE-0001 recusal are entries 1 and 2), governance/first-session-agenda.md (the twenty interim
resolutions triaged into ratification buckets) and governance/member-brief.md (the reading
path in, and the habits of the record).
Added — the requirements extension, spec-first, and the defect rows that ground it
docs/extensions/requirements.md (Working Draft — spec; schemas to follow): Requirement and
RequirementSet as first-class, versioned, addressable objects; three closed relation types
(derivesFrom, varies with a mandatory Decision as authority, testedBy); statement patterns
adapted from EARS with deterministic checks only; parameters declared on the requirement and
bound on the set; tenancy, quality assessment and requirement content explicitly out of scope.
The three core sockets it relies on are proposed, not shipped, and the spec says so.
Grounded by defect rows rather than argument: D-34 (no object addresses an evaluation
criterion), D-35 (Obligation records what discharges it and nothing about where it came
from), D-36 (a submission cannot state a structured position on what was asked), D-37
(two core identifierScheme codes collide with the extension prefix grammar), D-38 (nine
in-tree extension roots lack the Part 1 pattern), D-39 (a generated bare enum would decide
gate C-4 by generator shape; resolved on the record as an amendment folded into IAR-0003's open
pull request — anyOf of the enum and the prefix pattern, plus a reservation rule for prefixes
already used by core codes). D-40..D-42 are recorded from verification candidates checked
against main, and D-43 records that forge state — pull requests, review decisions — is
invisible to tree evidence, with three instances of records asserting forge state that did not
hold; it closes when the inventory extractor gains a forge section or such assertions are
forbidden.
.github/ISSUE_TEMPLATE/scope-enquiry.md adds the intake route the originating enquiry had to
do without; SE-0001 is the first record through it, filed with the recusal attached.
Added — dialect tooling, report-only
tools/migrate-2020-12.js (mechanical Draft-07 → 2020-12 rewrite) and
conformance/rules/check-dialect-equivalence.js (identical verdicts across the corpus under both
dialects). Report-only until the v1.0 train decides the migration; a reported verdict difference
is evidence for that decision, not a failure of this one.
Changed — CI: the binding step is temporarily non-gating, with its revert condition stated
The closed-codelist binding step carries continue-on-error pending IAR-0003 as amended, whose
branch generates the enums and fixes the four failures the step reports (D-14, D-30 — both
unchanged by this). The failure stays visible as a warning annotation on every run, and the
revert travels with that merge: the check goes hard again at the moment it starts passing. One
dated workflow statement instead of repeated required-check overrides.
Added — the wiki becomes a projection
tools/wiki-sync.js: the live GitHub wiki has no pull requests and no CI of its own, so it is
treated as a projection of the reviewed wiki/ directory, never an editing surface. The check
mode reports drift in both directions — a live-only page is D-33's pattern and requires a human
decision — and every push records the source commit, so each live-wiki state traces to a
reviewed tree state.
Fixed — the specification's self-description, and the registry it named but did not have
docs/specification.md was the second record to keep the corrected wording out. The v0.16.0
reconciliation replaced the claim that Concert "stewards its evolution through the Standards
Committee" with the bootstrap-honest formulation, and landed it in §12.2 — which states plainly
that no Standards Committee is constituted — while the same claim survived twenty-two lines
from the top of the same file, in "About this document". One document, two statements of the same
fact, corrected in one place and not the other. governance/defects.md D-33 records the wiki as
the third record to drift on this claim; the pattern is not a missed line, it is that the
repository holds the same governance fact in several hand-maintained places and nothing compares
them.
The status header was stale in a second way. It read "Specification v0.1 (Working Draft)" and
"Status: Request for Comments", and "About this document" said field-level definitions were
"illustrative" and "not yet frozen" — against a repository with a machine-runnable conformance
suite, four certifiable extensions, a normative state model and an interims register. The header
now separates the two identities that were being conflated: CDM v0.1 is the version-stable
namespace at https://concert.foundation/signet/v0.1/ and does not move with the repository
release. The release number is deliberately not restated in the document. It has a single
source in package.json, is rendered into the published page by tools/build-pages.js, and is
pinned for the website by standard-ref.mjs; a fourth hand-maintained copy would be stale at the
next release, which is the defect being fixed rather than a fix for it.
Also corrected in the same class:
docs/specification.md"About this document" cited §11 for change control. Change control is §12; §11 is Extensions. The cross-reference had been wrong since the section was written.docs/extensions/README.mdstated that "Standards Committee decision records are published undergovernance/reviews/". None of them is a Committee decision, because there is no Committee; each is an interim resolution taken under the bootstrap clause.docs/extensions/README.mdnamed the Committee as the operative route for promoting an extension toward the core, anddocs/profiles/auction-platform.mdreferred a grammar question to it. Both now say what is true today and what changes on constitution.
Fixed — the same class in the other hand-maintained records, and what the pattern shows
governance/README.md stated "Twenty interim resolutions are currently in force, across four
documents" directly above a table of seven — D-33's fourteen-lines-apart shape compressed to
one line. The count is removed rather than corrected: the table is the record, and a number
restated in prose drifts out of step with it the moment a resolution is adopted. This is the shape
the site checker now forbids on /governance, so the two records fail the same way or not at all.
wiki/Home.md, wiki/FAQ.md and wiki/Governance-and-Versioning.md carried the same "v0.1
(Working Draft / Request for Comments)" / "not yet frozen" self-description that
docs/specification.md carried, and two of them stated the repository at v0.10.0. All are
corrected the same way as the specification header: the CDM-versus-release identities are
separated, and the release number is removed, not re-pinned. A hand-typed release number in
wiki prose is the drift mechanism itself, and six releases is the proof.
The asymmetry is the finding, and it is recorded as a dated note on D-33 rather than a new row.
The v0.16.0 reconciliation corrected the Standards Committee clause in both records —
docs/specification.md §12.2 and wiki/Governance-and-Versioning.md:17 each say plainly that no
Committee is constituted. The version claim was corrected in neither, surviving
simultaneously in the spec header and on three wiki surfaces. The sweep discipline therefore works
per topic, not per record: a reconciliation fixes the clause it was called for wherever that
clause appears and leaves every other stale clause in the same paragraph standing. D-33's closure
condition is widened accordingly — the cross-reference check it waits on must compare version and
status claims, not only enums and process, or the next reconciliation passes over them again.
One further clause: wiki/Home.md, wiki/FAQ.md and the release-history table in
wiki/Governance-and-Versioning.md were frozen at exactly 0.10.0, and _site/index.html
states the same 0.10.0 under D-23. Four surfaces at one value is not four independent lapses — it
dates the last sweep and says the remedy is regeneration rather than editing. The release-history
table was subsequently cut rather than backfilled; see below.
Changed — wiki/ is scanned by the naming check, and the release table is cut
conformance/rules/naming-denylist.json adds wiki to its scan list. The rule that Concert
names no individual and no commercial implementer covered docs, governance, codelists,
schema, conformance and state-model. It did not cover wiki/ — which tools/wiki-sync.js
projects to the public GitHub wiki, a Concert-voiced surface with no pull requests and no CI of its
own. The rule applied to it on paper and no check ever read it. That is the D-19 shape exactly: the
defect is the absent control, and no breach is asserted. check-naming.js's fallback list is kept
in step so the two copies cannot disagree; no rule logic changed.
Structurally the newly-scanned files are clean. Salted digest detection needs
SIGNET_NAMING_SALT, which is held in CI and not in the repository, so the first pass with name
detection actually on runs in CI for this change — not locally, and not before now.
The release-history table in wiki/Governance-and-Versioning.md is cut, replaced by a pointer
to CHANGELOG.md as the single release record. A table of releases in a wiki page is a second
hand-maintained copy of the changelog — the file class this workstream exists to remove — and it
drifted as a second copy does, stopping at 0.10.0 for six releases. It is cut rather than
backfilled: six release summaries is authoring, not a correction. The finding is not lost, because
it never lived in the table — D-33's dated note records the stale value as evidence dating the last
sweep of these pages, and the register keeps the history of the drift while the drifting artifact
goes.
Added — the certification register
conformance/certification-register.md: normative, closed, append-only, zero entries.
conformance/certification.md has specified a public registry since it was written — §2 step 4
issues into it, §3 makes the registry record the source of truth and licenses a short-form mark
only against "a resolvable link to the registry entry", and §3.1 lists an entry's fields. The
artifact did not exist, so §3's resolvability condition was unsatisfiable by construction and a
published news post promised implementers a listing in a register that could not be read. That is
the D-31 / D-40 family — a released or published record citing an artifact absent from the tree —
and it is now recorded three times over, which is the argument for a check rather than for closer
reading. Recorded as D-44.
The register opens empty and says so in its own header: emptiness is the accurate state, not a
gap in the file. No certification has been issued to anyone, including Score Networks. It is
indexed from governance/README.md, linked from certification.md §2, §3 and §3.1, and declared
published in public-interface.json, so check-public-interface.js fails if it is ever removed
— the register cannot now go missing the way the artifact it replaces never arrived.
governance/README.md's series-gaps note is corrected with it: it stated the defect register ran
to D-31 when it runs to D-44, and listed D-33 as reserved on an unmerged branch after that branch
merged.
Added — repository inventory extractor (non-normative tooling)
Added tools/inventory/inventory.js: a dependency-free repository inventory extractor producing
signet-inventory.json (schema v2), a CLAIMS.json verifier for evidence-bound repository claims
in handoff packs, and a CI self-test with the inventory uploaded as a workflow artifact. The
inventory is generated, not committed.
Scope is git ls-files. The extractor states what the tracked tree contains — manifest with
per-file hashes, schemas with their full field universe, codelists with the register line that
decided closure, the state model, conformance requirements and checkers, and the whole text of
every tracked Markdown file — and classifies nothing as correct, stale or missing. Where a fact
is derived, the line that decided it is recorded alongside.
referencedFields splits every backticked Object.field in tracked prose into shipped, proposed
and unresolved against the schemas. It is data, not a gate: making it a gate would fail builds on
prose that is already merged, and belongs in its own change proposal.
A claim in a CLAIMS.json with no evidence fails verification rather than warning. A marker that
can be read past is not a control.
Changed — implementer review of v0.15.0, and three defects it found in four-day-old artifacts
A twenty-one question enquiry from a deploying implementer, answered at
governance/RESPONSE-2026-08-implementer-enquiry.md. Corrections landed before the response was written,
so the response describes the repository rather than promising it.
docs/state-model.md §2a — CDM status is market-facing (normative). A core state vocabulary
describes what a counterparty can observe, not a party's internal governance. This is not a new
decision: every core edge must be justified from OCDS, the Procurement Act procedures, UBL /
EN 16931 or ePO, and none of those models a buyer's internal review, so an internal-governance
edge could never satisfy B-1. Core status has been market-facing by construction since the basis
rule landed. Internal workflow goes to a namespaced profile with a declared coreEquivalent;
extending a core vocabulary to carry it is forbidden.
§6 B-3 — externality is not generality. B-1 asked only whether a basis was external to the
implementer. A national procurement act or a sector security regulation passes that and still
should not oblige every implementer in every market. Each basis now carries a scope — general,
jurisdictional, implementer — and only general justifies a core entry alone. When the check
was first run it flagged two core edges in this repository's own registry; both were
corroborated against a general source rather than the check being relaxed. (D-16)
§5 R-3 — derived predicates. A condition computable from another object is neither a state
nor an annotation. An Evaluation is "consumed" when an Award references it; that is a fact
about the graph, and storing it creates a value that can drift.
§5a — controlled reopen. A transition, not an annotation. A terminal: true state cannot be
reopened; an edge marked requiresAuthority must name a decisionType, so the requirement cannot
be documented and left unenforced.
§4a — entry-kind test. Does something exist that did not? Creation. Does this object's own state differ? Transition. Is a fact recorded about it? Annotation.
§11 — derived artefacts. Where two records of one relationship exist, keep one and generate
the other. sourcingEvent.published drifted for this reason and so did the closed codelists.
Contributed by an implementer who measured it: 58 of 68 policy gates carried a transition label
disagreeing with the state the rule tested.
Changed — the process claim reconciled with the record
docs/specification.md §12.2 and wiki/Governance-and-Versioning.md had said since v0.1.0 that
the core model changes "through the formal revision process governed by the Standards Committee,
with a published comment period." Two things were wrong with that. No Standards Committee is
constituted. And of the twelve normative changes made between v0.1.0 and 20 August 2026, none
carried a comment period.
Both now state the rule that actually applies — a recorded resolution, a stated comment period of at least fourteen calendar days, and an approving review, every change by pull request — say that it took effect on 20 August 2026, say that no Committee is constituted, and point at the audit for what preceded it.
governance/IR-2026-08-prior-normative-changes.md— an interim resolution covering the eleven normative changes that carry no approval record. They stand; they are recorded as predating the written rule rather than as having satisfied it; and it is one resolution rather than eleven back-dated approvals, which would be a fabrication of evidence. It is not an assessment of merit: every one passed CI, and the commodity-risk extension was reviewed twice on the record.- Both commodity-risk review memos gain a note recording the arrangement under which they were taken. They are titled as Standards Committee reviews and no Committee existed; their closing line, "Recorded for the Standards Committee," is accurate, but the titles read otherwise. The titles are left as written rather than changed after the fact.
governance/README.mdnow indexes the interim approval record, the interim resolution, the withdrawal, and the drafted site corrections, so the bootstrap-clause table is the single index it claims to be.
Closed out, and outside this repository: concert.foundation/governance no longer presents the
Standards Committee as a currently operating body. The drafted correction at
governance/site-alignment/ was superseded before it was applied — the live page already said what
it proposed. The outcome is recorded at governance/site-alignment/OUTCOME.md. Three claims the
draft did not examine are addressed in concerthq/concert-website.
Fixed
-
Registry completed to all 29 objects, up from 9. §L-2 has said since v0.15.0 that statelessness by omission is a defect. The registry reproduced that defect in the artifact that defines it.
Evaluationis now declared a terminal record. New check C12 fails any schema file without a declaration. (D-15) -
Closed codelists bound. Not enforced — see the correction below. Five were
"type": "string"with the CSV named only in a description;{"procedure": "banana"}validated.codelists/bindings.jsonbinds each closed codelist to the schema location whose enum it governs, andcheck-codelist-binding.jsasserts that the CSV and the enum agree and, with--write, generates the enum from the CSV. Those two artifacts are what landed here. (D-14)Corrected 2026-08-21. This bullet was headed "Closed codelists enforced" and ended "Tier 2, landed under
governance/IAR-0003." Both statements were wrong. The binding manifest and the checker landed at v0.16.0; the generated enums did not. Generating them altersschema/, which is normative, so it is a Tier 2 act undergovernance/IAR-0003— and that record's pull request has never been opened, so its comment period has never started. Onmainat v0.16.0, five closed codelists carry noenumat the bound property and any string validates against it:{"procedure": "banana"}is accepted today, in the present tense, exactly as this bullet says it once was.check-codelist-binding.jsfails on four of the five and records the fifth,identifierScheme, as a binding deferred pending D-20. It was not wired intovalidate.yml, so nothing surfaced the gap. The tag is not amended — the correction is recorded here, in the entry that made the claim, and as D-30. D-14 is reopened. -
codelists/submissionStatus.csvdeleted. It duplicated the vocabulary carried inline onSubmission.statusand was referenced by no schema. The inline enum is the single record, as for every other lifecycle-bearing object. The binding check fails if the file reappears. (D-13) -
Terminal reachability. Check C11, contributed: every lifecycle-bearing object must have a terminal state and every state must be able to reach one. Distinct from C9, which asks only whether a state can be entered — C11 catches an object that can never end.
-
State vocabularies are now generated from the registry, not merely checked against it. §11 said a second hand-maintained copy is a defect; state vocabularies were exactly that, so the rule was violated by the artifact that states it.
check-state-model.js --writegenerates the schema enum from the declared states. This promotesstate-model/state-model.jsonfrom informative to normative for every lifecycle vocabulary it declares — a normative enum cannot be derived from an informative source — so the file gainsCODEOWNERSprotection and a change to a declared state is Tier 2 wherever it is made. Landed undergovernance/IAR-0004. Objects declared lifecycle-bearing but not yet modelled keep their vocabularies. (D-18) -
codelists/submissionStatus.csvrestored, retired but resolvable. Deleting it under IAR-0003 madeconcert.foundation/signet/v0.1/codelists/submissionStatus.csvreturn 404 — a published URL in the$idnamespace, proxied frommainwith no cache and no fallback — and failed the site build cold on a second consumer. IAR-0003 stated the file had no consumer; two existed inconcert-website, and neither was recorded in this repository, so the claim was unfalsifiable from inside it. That is the defect, not the deletion. The file is restored byte-identical to what was deleted, bound to no schema and absent fromclosed;codelists/bindings.jsoncarries the disposition andcheck-codelist-binding.jsnow distinguishes deleted from retired-but-resolvable, failing in both directions. Retirement says nothing is maintained here; it does not say the URL may stop answering. Landed undergovernance/IAR-0005. (D-24)
Added
docs/absence-discipline.md. Empty, null and absent are three states and only absence fails open: an undefined operand yields an undefined rule body and the rule does not fire. Every negative fixture requires an absence twin. Contributed from a measurement of 259 references across 68 gates, published de-named.conformance/rules/check-naming.js. Concert names no individual and no commercial implementer. That rule has existed since v0.13.0 and was enforced by nothing — the defect is the absent control, and no instance of a breach is identified in the repository. The deny-list is stored as salted digests, never as terms — a published list of names that must not appear is the disclosure it exists to prevent — with the salt held in CI. Verbatim third-party documents are excluded, with the reason recorded in the manifest so the exclusion is auditable. (D-19)governance/defects.md. Promoted out ofWITHDRAWAL-2026-08.mdso that record stops accreting. Twenty-five entries at this release — twelve closed, twelve open, one in progress.governance/REVERSAL-RISK.md. Each interim resolution gains a band and reasoning, answering an implementer question about which of twenty unratified decisions carry reversal risk. Eighteen are unassigned, and unassigned reads as unassessed rather than low.
Governance
-
governance/IAR-0005-published-url-restoration.md— Tier 2, under the bootstrap clause, restoring the published URL above. Its stated fourteen-day comment period did not run. The record was merged on the day it was opened, because the period would have extended a live 404 by fourteen days.That is recorded as a departure, not an exemption.
GOVERNANCE.mdrequires the period before merge for every Tier 2 change and names no exception for urgency, and the carve-out ingovernance/WITHDRAWAL-2026-08.mdis an exception to the proposal moratorium that itself requires a stated period. The rule applied and was not observed, andGOVERNANCE.mdnames such a merge a defect in this process. The stated period is left in the record verbatim and the departure is recorded beside it, on the shape ofIAR-0002. Comment remains open for fourteen days from merge; the change will be reversed or amended on sustained objection. What does not stand is any claim that this record followed the process in full. (D-29) -
Four defects recorded since the register was drafted. D-24 closed — the 404 above. D-27 open — the repository declares no public interface, so a claim that a file has no consumer is not testable from inside it. D-28 open —
codelists/*.csvadmits no comment line, so the format cannot record that a file is retired. D-29 open — it closes whenGOVERNANCE.mdgains a carve-out for a defect actively causing harm, adopted under its own Tier 2 route. D-25 and D-26 are reserved for the site-pinning work and are not recorded here.
Note on interests
The enquiry is signed by the same natural person who operates both stewardship identities — the
most acute instance of the disclosed overlap to date. Accordingly the enquiry is published
verbatim, the response carries the full comment period with no waiver, and no correction here
rests on the enquiry's evidence: each is verifiable against schema/, codelists/ and
conformance/ by a reader who has never seen it. Contributed patterns are adopted as evidence,
published de-named, and are never basis.
The bootstrap arrangement was scoped to let design proceed without a Committee. It was not scoped to absorb a public enquiry from the steward's own implementer alongside twenty unratified resolutions. The governance load, not the design load, is now the binding constraint.
Added — the state model: surface authority, a transition registry, and the basis rule
Design principle §1.7 and conformance/levels.md GRT-1 both say the event stream is
authoritative. Neither was executable: projecting a stream into a state needs a mapping from
events to state changes, and no artifact published one. Mandate asserted a lifecycle it could
record on no surface; sourcingEvent.published named a state the enum does not contain; nine
objects carried a state field and one rule governed none of them.
- Surface authority stated generally (
docs/state-model.md§2). Current state is the projection of the event stream. A stored state value is the serialising party's assertion as atprovenance.generatedAtand MUST equal the projection at that instant; between parties holding the stream, the projection governs. This generalises GRT-1 from grant-type objects to all objects, and supplies the rule whose absence was the stated reason status fields onConsentwere rejected. No field is added to any object — that rejection is closed out, not reopened. - Transition registry (
state-model/state-model.json). Three entry kinds — creation, transition, annotation. Every state declaresterminal,appendable, and a terminalclassof completion / abandonment / revocation. Event codes may serve several entries provided their source sets are disjoint, which is what makes projection a function. - Relations are not states; outcomes may be (§5).
Bid.supersededis a relation and cannot be projected — removed from the enum and expressed as abid.supersededannotation event carryingsupersededBy.admissible,winning,approvedandqualifiedare outcomes of Decisions, are projectable, and stand unchanged. - The basis rule as a CI check (
conformance/rules/check-state-model.js). Every core entry must name an external justification — OCDS status codelists, the Procurement Act 2023 procedures, UBL/EN 16931 lifecycles, ePO, or a named instrument. An edge justifiable only from one implementer's workflow goes to a profile. This is the neutrality control, deliberately automated rather than left to review: it runs on every push and is auditable after the fact. - 21 open codelist values added to
codelists/eventType.csv.eventTypeCore.csvis untouched. - A reachability defect fixed without a schema change. A
Submissionruledadmissiblecould not reachwithdrawnunder any reading of the enum. The registry permits the edge.
Coverage is reported, not assumed: five of eight lifecycle-bearing objects are modelled.
OnboardingCase, SupplierQualification and HedgeProposal are declared lifecycle-bearing and
not yet modelled — their edges need a basis from the extension maintainers.
ExposurePosition.positionStatus is declared non-lifecycle: it classifies what a position
is, and reconciliation depends on it as a category.
No conformance requirement is added. This is modelled and specified, not certified. An
F-STATE requirement belongs at Full and is deferred.
Four of the five artifacts are Tier 1. The one Tier 2 item — removing superseded from
Bid.status — lands under the bootstrap clause per governance/IAR-0002-state-model.md.
Landing does not ratify.
The fourteen-day comment period was waived. It opened on 20 August 2026 and would have
closed on 3 September; the change was merged on 20 August by explicit decision of the repository
owner. This is a recorded departure from GOVERNANCE.md Tier 2, not an interpretation of it,
and it is written into governance/IAR-0002-state-model.md rather than left to be inferred from
the merge dates. No comments were received, because there was no interval in which to receive
any. The change stands on its merits; what does not stand is any claim that it followed the
process in full.
Changed — the v1.0 proposal train withdrawn; its findings kept
The seven registered proposals are parked, not rejected, per
governance/WITHDRAWAL-2026-08.md. Registration is Tier 1 and adoption is Tier 2, so a queue
that costs one review to grow and a Committee to clear will grow without bound. Eight defects
are extracted and recorded as facts about current artifacts; five are addressed by the change
above, three stand open. No further proposals are registered until the Committee is constituted,
except to correct a defect actively causing harm.
Found — one of twelve normative changes carries an approving review
An audit of every commit since v0.1.0 touching a Tier 2 path, at
governance/reviews/2026-08-normative-approval-audit.md. Twelve commits qualify. One carries
an approving review; two carry a written approval record of any kind; four reached main as
direct commits with no pull request; none had a stated comment period, which the
specification and CONTRIBUTING.md have claimed for normative changes since v0.1.0.
Nothing merged is thereby wrong — every commit passed CI, and the commodity-risk extension was reviewed twice on its substance. The gap is in evidence of process, not in care. But it means v1.0 cannot currently claim its normative content went through the process the specification describes, which is the same shape as the two conformance findings behind the endorsement proposals. Recorded before the fact rather than after someone else establishes it, and deliberately not relabelled: the audit recommends one resolution acknowledging the eleven as predating the written rule, not eleven back-dated approvals.
Added — GOVERNANCE.md: the review rule, written down
The rule was being followed by habit. Writing it down now makes it a choice; writing it after someone observes that normative changes were merged by a second account under the same control would be damage control, and would read as such.
- Two-tier review, by pull request only. Tier 1 (non-normative) takes one approving review
and no comment period. Tier 2 (
schema/, closed codelists,conformance/levels.md, the suite, the report schema — and the mark grammar and the two closed registers, which are normative for licensees rather than CDM artifacts) additionally requires a recorded resolution and a stated comment period of at least 14 calendar days. Direct commits tomainare not a permitted route for any change of any class. - The Standards Committee is not constituted, and the document says so. It will be
constituted at the first external certification — externally observable, and not
quietly deferrable. Until then decisions are interim resolutions under the bootstrap clause,
which stays authoritative in
governance/README.mdand is referenced rather than paraphrased. - The two repository identities are disclosed.
concertfoundationauthors;concertcustodianreviews, approves and merges; both are operated by the same natural person. The separation is procedural, not independent, and the document says that in those words. A governance document that implied independence it lacks would be worse than none, because it would convert an undisclosed limitation into a false statement. - Registration is not adoption.
governance/proposals/is non-normative: a proposal's presence in this repository is not a statement that it has been accepted, and it is not part of the standard. - An effective date, and no retroactive relabelling. The process applies from 20 August
2026. Earlier changes followed prior practice — including direct commits to
mainand pull requests merged with administrative override — and are recorded as superseded, not as having followed a rule that did not exist.
Found — the published governance page contradicts the repository
concert.foundation/governance presents the Standards Committee as a currently operating body,
with a membership composition. The repository states that none is constituted, and twenty
interim resolutions are in force precisely because none is. A draft correction for the page is
recorded at governance/site-alignment/, not applied — the page is outside this
repository. This is the same class of defect the claim triad exists to catch: a body that is
designed being described as one that is operating.
Superseded. The drafted correction was overtaken before it was applied; the live page already
stated what it proposed. Recorded at governance/site-alignment/OUTCOME.md.
Added — the v1.0 train, specified and registered (not started)
Four further proposals from a second round of multi-market, multi-tenant implementation questions, plus an amendment record that revises two of the existing ones. Nothing here touches a normative artifact. The seven proposals that make up the v1.0 train are registered so the train can be planned, sequenced and estimated; twenty-two gates are open and every one of them is for the Standards Committee.
- CP-EventType-Closure —
eventTypehas eight values for eighteen objects and stops atcontract.signed; the entire implementation stage has no codes. The gap is already being filled silently: an implementation that places an Order must emit an Event, there is no code for it, so it mints one and passes conformance. The proposal derives the vocabulary from the existing lifecycle enums and checks it in CI for drift, rather than curating it by hand. - CP-Policy-Applicability — every gate in
the model is opt-in at instance level: a
Policythat is never cited is never applied. AddsPolicy.appliesToand a derived required-set, with a newF-GATErequirement at Full. - CP-Mandate-Scope —
Mandate.scopeis required and completely unconstrained.{}satisfies it. Adds structure, and anF-SCOPErequirement whose limit is stated rather than left to be discovered: SIGNET can test what an agent declares it read, not what it actually read. - CP-Process-Spine —
SourcingEventhas no link back toNeed, the one break in an otherwise fully linked spine. One optional field. The only item in the set that delivers value alone, and a candidate for an earlier v0.x minor. - CP-Amendments-Round-2 — recorded as a
reviewable amendment rather than folded silently into what it touches, and applied to both.
§A1 adds same-tenant event chaining to CP-Tenancy; §A2 dissolves gate
C-3in CP-Codelist-Enforcement.
Two gates dissolved rather than resolved, which is why the train's gate count fell from twenty-four to twenty-two:
- Event chain partitioning. The question — is the chain partitioned by tenant, or one chain with tenant recorded per event — is well-formed, and the model answers it in neither of the terms offered. The chain is per subject: there are as many chains as there are subjects. There is nothing to partition, so isolation becomes a conformance rule over the existing structure. What that does not give you is stated too: there is no total order within a tenant, and any tenant-level ordering is a projection an implementation constructs.
C-3retirement semantics. A closed vocabulary over an append-only stream cannot retire a value, because retirement means "no longer valid" and every historical event asserts otherwise. Codes are never retired. Thediscouragedmarker becomes guidance in the non-normative disposition file; the fourth CSVStatuscolumn is declined with its reasoning, because it is the obvious answer and will be re-proposed otherwise.
Added — extension composition, part 1: namespaced private fields
Proposed under CP-Extension-Composition and
landed ahead of ballot under the bootstrap clause: schema/ and conformance/suite/ are
normative, so it went through the change-proposal path rather than a direct merge, non-breaking
though it is. Landing it does not ratify it — the proposal remains a draft until balloted, and
the Standards Committee may amend or reverse it.
The Extensions page has always told implementers to add structure "under their own namespace."
Against the published schemas that instruction was unexecutable: every object schema sets
additionalProperties: false, so an ERP company code, a cost centre or an internal approval
reference could not be carried at all without failing document conformance.
- Object schemas now permit namespaced properties. A
patternPropertiesentry admitting^[a-z][a-z0-9-]*:[A-Za-z][A-Za-z0-9]*$sits alongside the unchangedadditionalProperties: false, at 22 sites: the 18 root objects,Obligation,Item,InvoiceLine, and the inlineLot. Soexample-org:costCentrevalidates, whileprocurringParty— a misspelling of a core field — is still refused, because it carries no prefix. That refusal is the property the wire contract rests on and it is untouched. - Say exactly what a prefixed field is. Permitted by the core schema and constrained by nothing. It is not modelled, not assessed by core conformance, earns no mark, and is never promoted into the core model without first becoming a published extension. Nothing here adds tenancy, market or marketplace support, and nothing here is a partial delivery of CP-Tenancy.
signet:andconcert:are reserved; barex-is forbidden. Both are enforced by the conformance suite rather than the schema pattern: a negative-lookahead regex works under Ajv but sits outside the portable ECMA-262 subset that non-JavaScript validators reliably implement, and a governance rule encoded there would be silently unenforced on exactly the implementations least likely to be checked. Prefixes are otherwise self-asserted and first-come — Concert operates no prefix registry.- Four fixtures, so the escape hatch is proven rather than asserted.
fixtures/valid/order-private-extension.json(new, and the load-bearing one) must validate;party-unknown-property.json(new) must be rejected;party-reserved-prefix.json(new) must validate against the schema and still be refused by C-DOC; andparty-bad.jsonis narrowed to thepartyTypeenum rule alone, itsadditionalPropertiesrole having moved toparty-unknown-property.json. Without the positive fixture a later schema edit could close the hatch unnoticed. - A JSON-LD corollary, documented so implementers do not meet it by surprise. A private prefixed field has no context mapping and is therefore dropped during JSON-LD expansion. That is semantically correct — a private field has no global meaning — and it is a useful forcing function: to survive expansion you must publish a context, which is the first step toward being an extension rather than a private field.
Non-breaking. Every instance valid before this change is still valid, and existing certifications are unaffected.
Added — the tenancy change-proposal set
Three linked proposals registered in governance/proposals/, arising from a multi-market,
multi-tenant implementation question. None is balloted and none is implemented beyond Part 1
above.
- CP-Extension-Composition — two mechanisms where the model conflates one: a private prefixed field (Part 1, above) and a composed published extension (Part 2, requiring the 2020-12 migration and therefore the v1.0 train). Three gates open.
- CP-Tenancy — tenant, market and marketplace are
three independent concepts and none exists in the CDM; today all three are carried implicitly
in the DID authority of an identifier, which is unpatchable once instances exist. Breaking, so
v1.0 or never. Four gates open;
T-4resolved as deferred — a network of SIGNETs is a roadmap item,Event.tenancy.marketplaceswould record the emitting node as attribution only, and no federation capability is claimed. - CP-Codelist-Enforcement — seven closed
codelists are enforced by nothing: they are
"type": "string"with a CSV pointer in a description, so"procedure": "banana"passes C-DOC today. Four gates open. It must land in or before the v1.0 train if CP-Tenancy does, or v1.0 shipsregulatoryRegimemodelled as closed and tested as open — the claim-triad failure the suite exists to prevent.
Added — governance: marks, registers, and two conformance findings
A single workstream. It began as a question about where implementation-roadmap collateral should sit, and drafting a competency framework against the actual JSON schemas rather than the wiki prose surfaced two gaps between what is claimed and what is tested. Those are the substantive discovery; everything else is consequence.
- The two findings.
Consenthas no conformance requirement — C-DOC validates it structurally and nothing tests that access is gated, that revocation takes effect, or thatDocument.accessGrantis honoured. And mandate enforcement is demonstrated, not certified — F-SEM requires aDecisionto citepoliciesApplied; nothing requires the limits in those policies to have been respected. An implementation that awards beyond anapprovalThresholdspolicy with nohumanApproval, while recordingunderMandateandpoliciesAppliedcorrectly, passes F-SEM and reaches Full. The record is well-formed, hash-chained, provenance-bearing, and false. Both are now stated plainly inconformance/levels.md§5 andconformance/README.md, whatever happens to the proposals below. governance/mark-grammar.md— the complete set of marks Concert issues, in one document rather than extended per requirement: three head terms never crossed (SIGNET Certifiedfor implementations,SIGNET Registeredfor people,SIGNET Accreditedfor training providers), an ASCII ABNF, short forms licensed only where they resolve to the registry, prohibited constructions, the wind-down windows, and what anyone may say without a licence. Six interim resolutions recorded with their reasoning. Marks as W3C Verifiable Credentials was considered and declined, with the reasoning kept because the idea will return.tools/lint-mark-strings.js(npm run lint:marks) — the ABNF, checked mechanically in CI, against the registers rather than a hard-coded list. It also fails the build on a superseded mark form or a prohibited construction anywhere in published copy.- Two registers, closed and append-only —
governance/endorsement-register.md(two entries, each recording the three-part admission test;Consent Enforcementcarries its scope limit in the register itself) andgovernance/role-register.md(four roles;Foundationsconfers no mark). governance/role-competency-framework.mdandgovernance/person-assessment.md— what a person must be able to do, stated by reference to normative artifacts, with the assessment mode declared per domain, plus the rubric and the binding appeals route that must exist before any person mark issues.- Four change proposals in
governance/proposals/, none balloted: grant lifecycle, mandate enforcement (E-MDT), consent revocation (E-CNS), and credential semantics. - Endorsements — a second, additive axis (
conformance/levels.md§2.4). Draft and not in force:conformance/rules/check-endorsements.jsruns twelve checks against two optional adapter surfaces (conformance/adapter/endorsement-adapters.md), decides no level, and licenses no mark. - A third planted defect in the broken adapter — an agent that cites its mandate and its policies correctly and does not enforce them. It passes F-SEM and fails E-MDT-1, in CI, on every commit. The distance between those two results is the whole argument for the endorsement, and it is worth keeping even if that proposal is declined.
codelists/eventTypeCore.csv— a closed, normative core subset within the openeventTypelist, withconsent.granted,consent.revoked,mandate.granted,mandate.revoked. The twomandate.*codes are promoted, not added: their meanings are fixed rather than changed. Protected by CODEOWNERS, andconformance/rules/check-codelists.jsasserts in CI that the open and closed files never intersect — a closed codelist whose closure depends on someone noticing is not closed.
Changed
- Specification §7.4 — grant-type objects and withdrawal. A normative defined term
(
ConsentandMandate, enumerated), the rule that withdrawal is an appended event and never a mutated field, and the effective/not-effective projection rule, reproducible by a third party from the event stream alone. No schema change —Event.subjectalready carries the grant identifier. No*.expiredcode exists: expiry has no actor, andEventrequires one. - Positioning corrected against the claim triad. Modelled, tested, and certified are
three different statements, and the copy blurred them — always in the direction that
overstates. The Architecture Overview no longer says conformance with the specification's MUSTs
"is decided mechanically by the Conformance Harness" without qualification;
Mandateis no longer "the structural guarantee that agents cannot exceed their remit"; and the auction profile's AP-4 now says it tests record completeness, not that the ceiling held. - The canonical mark form is now
SIGNET Certified: Full (CDM v0.1, suite v0.1)— ASCII, colon-delimited, lintable. The em-dash form is superseded and CI rejects it. Consent.purposeandConsent.revocabledescriptions —purposeis a human-readable statement, not a machine-evaluable term, with the profile extension path stated;revocableis a capability flag, not a status.
Note on status
Nothing here has been balloted. Twenty interim resolutions are in force under the bootstrap clause, each ratifiable, amendable, or reversible by the Standards Committee once constituted. CP-Grant-lifecycle is the only item that must clear before v1.0; its mechanism is landed ahead of ballot because closing a codelist subset is materially cheaper before publication under a stable URI and DOI than after. Neither endorsement proposal gates v1.0 — both must land before the first certification, which is a separate and later constraint.
Added
- Auction conformance profile — the first product-certification path
(
docs/profiles/auction-platform.md), composing entirely from shipped artifacts: it names five demonstrable requirements (valid objects, deterministic close, tamper-evident record, governed awards, no PII in the chain) checkable with the public suite. - Extension conformance rules — executable cross-object checkers for the onboarding (case↔qualification closure, conditional integrity), auction (the recorded winner equals the deterministic close; reserve integrity), and identity (Full-level: humanApproval resolves both ways; approver ceiling covers the decided value) extensions, wired into CI. All four extensions now have machine-backed conformance. Governance: commodity-risk resubmission record — merged as Working Draft.
- Five P2P/SRM extension specs (Working Drafts, spec-first) — receipt & governed three-way match; supplier performance (SLAs as Policy, assessments feeding the qualification lifecycle); contract amendments (event-anchored deltas, derived state); framework agreements & call-offs; negotiation under per-term mandates. Schemas and conformance rules follow per-extension after review, per the process established by commodity-risk.
Added
- Onboarding extension spec at
docs/extensions/onboarding.md(previously undelivered; schemas and demo shipped in 0.6.x). - Commodity-risk extension — technical artifacts. Six schemas (ExposurePosition,
CoveragePolicy as a Policy subtype, PriceMark, CoverageAssessment, Scenario,
HedgeProposal), ten codelists (positionStatus and policyEvaluationStatus closed),
an eleven-file full-loop worked example (belowMinimum → proposal → executed →
withinCorridor, arithmetically reconciled), and the six conformance rules as an
executable checker (
conformance/rules/check-commodity-risk.js) — three are cross-object checks beyond schema validation: reconciliation arithmetic, scenario fixed-cost invariance, escalation-first rule ordering. Completes the extension accepted in principle ingovernance/reviews/2026-07-commodity-risk.md.
Added
- Identity profile (Working Draft) —
docs/extensions/identity.md: how SIGNET represents natural persons. Humans act under Mandates (coreMandatereused —agentaccepts any actor); authority is adelegationOfAuthorityCredential; newApprovalobject makeshumanApprovalresolvable and verifiable (approver pseudonym, role, authority credential, provenance). Normative no-PII rule for hash-anchored records (pseudonymous person references only; resolution is an organisational obligation). Authentication is out of scope by design. The agent demo now emits the verifiableApprovalat runtime and checks the approver's authority ceiling covers the award value. - Commodity-risk extension (Working Draft spec) —
docs/extensions/commodity-risk.md: portfolio-level commodity risk governance (positions, coverage corridors as Agent-layer Policy subtypes, price marks, assessments, scenarios, hedge proposals bridging to coreNeed). Accepted in principle by the Standards Committee (governance/reviews/2026-07-commodity-risk.md) — the first member-proposed extension, reviewed under the identical process as any proposer. Schemas, worked example, and conformance rules to follow as a separate change.
Changed
- Documentation & demo alignment. Brought the repository's prose level with its code:
the top-level
README.mdnow documents the conformance harness, the three demonstrations (agent award, onboarding, auction) with their current outcomes, and an Extensions & profiles table with per-item status.agent/README.mdwas corrected to the current MAT weighting (price 0.20 / quality 0.55 / social 0.25 — the dearer, higher-quality bid wins 0.859474 vs 0.8415) and the verifiable-Approvalcheck. Extension specs are consolidated underdocs/extensions/<id>.md(the auction spec renamed toauction.md) with a newdocs/extensions/README.mdindex; the wiki sidebar points at the specs and demos. No schema or normative change.
Added
- Auction extension — process-layer objects
Auction(a profile of the sourcing flow; reverse / english / dutch / sealed-bid / multi-criteria viaauctionType+ deterministicrules) andBid. The auction rules and canonical bid record are normative and operator-independent — any conformant operator closing the same bids under the same rules MUST reach the sameAward. The close reusesDecision/Award; eligibility ties toSupplierQualification; the bid history is a hash-chainedEventtrail. OpenauctionTypecodelist; reverse-auction worked example. Modelled on Prozorro's neutral-core architecture: price formation in the standard, UX in the operators.
Added (all optional, non-breaking)
- Settlement linkage — makes the commitment→discharge loop traversable as data
(Concepts of Open Commerce §9, the Settlement primitive):
Obligation.dischargedBy— references the Order/Invoice/Document(s) that discharged the obligation. SHOULD be present oncestatusismet.Invoice.settles— references the Obligation(s) the invoice settles. SIGNET-original: it is not an EN 16931 Business Term and is omitted on the Peppol BIS projection, so ViDA convertibility is unchanged. A new projection-skip guard (npm run test:projection-skip) provessettlesnever leaks into UBL.eventTypecodelist:obligation.discharged.- Three worked fixtures, all conformance-checked: a discharged obligation, a
pending obligation carrying neither new field (the machine proof the additions
are optional), and an invoice with
settles.
- Referent granularity uses a composite
contractId/obligationIdURI (option (a));Obligation.idis unchanged. No existing field changed; documents valid before this release remain valid.
Changed (non-breaking; examples only)
- MAT evaluation policy reweighted to price 20% / quality 55% / social value 25%
(was 40 / 35 / 25). The change is carried in the policy's own
expression(score := price*0.2 + quality*0.55 + social*0.25) and itshumanReadablestatement;examples/policy-evaluation.jsonbumped toversion: 1.1.0. The agent demo reads the weights from the Policy expression, so its trace and scores regenerate from this single source. - Award scenario now demonstrates a justified price premium. Under the new
weighting the dearer bid wins:
submission-5521(€11.4M, quality 0.9, social 0.7) scores 0.859474, ahead ofsubmission-5522(€10.8M, quality 0.78, social 0.85) at 0.841500 (margin 0.017974) — a 5.56% price premium accepted on materially higher quality. The demo is now a proof of governed multi-criteria judgement rather than a low-bid pick.examples/award-decision.json(Appendix A) and the agent run resolve to the same winner, weights, and scores. - The award value (€11.4M, the winning bid) remains intentionally distinct from the
contract value (€12M, the category tier) in
examples/contract.json: awards are struck at the bid, contracts at the tier/ceiling. No schema or normative-grammar changes; sub-criterion scores are unchanged, only the weighting and resulting totals.
Added
- Supplier onboarding extension — process-layer objects
OnboardingCase(buyer-internal workflow; invited + submitted entry; revalidation/remediation case types) andSupplierQualification(durable status with first-classconditionalqualification, value caps and category restrictions). Reuses Credential/Policy/Decision/Event/Consent. Screening results carried as attestations, never performed by SIGNET. OpencredentialTypecodelist; two worked examples. Workflow states are normative; credential types are extensible.
Added
- Agent demonstration (
agent/) — a runnable proof that a synthetic agent can take a governed, accountable, conformant action. An agent reads a SourcingEvent, is bounded by a Mandate (its €12M value exceeds the €10M autonomous ceiling, so human approval is required), applies the published MAT evaluation Policy (weights parsed from the Policy's own expression), and emits an Award Decision with rationale, inputs, policies applied, human approval, and provenance — plus a five-event, hash-chained audit trail.agent-card.json(A2A),mandate.json, twoSubmissionbids, assessment inputs.reasoner.js— the pluggable "Model" (deterministic default; marked seam for a live frontier model via MCP/A2A).agent-runtime.js— the "Harness": mandate gate, policy application, provenance, event-chaining.run-agent.js— runs the scenario, narrates it, and verifies the output is conformance-clean (every object validates; chain holds; tampering detected).LIVE_MODEL_NOTE.md— how to swap in a real model for a live demo with no change to the harness.
- CI now runs the agent demo on every commit; its output must validate and the event chain must hold.
Added
- Conformance harness (
conformance/) — the machine-runnable suite behind the "SIGNET Certified" mark. Implements CDM §13 and the certification neutrality rules CN-1…CN-4.levels.md— Core vs Full levels; requirements C-DOC, C-EVT, C-PROV (Core) and F-MAP, F-SEM (Full); CN neutrality rules.certification.md— the identical-for-all certification process.runner/run-conformance.js— runs the suite against any implementation via a small adapter, emits a machine-readable report, computes the level achieved.adapter/reference-adapter.js— a complete conformant implementation (reaches Full);adapter/broken-adapter.js— deliberately non-conformant, failed by the harness at C-EVT and F-MAP, proving the suite discriminates.- Positive + negative document fixtures (invalid documents that MUST be rejected).
report-schema.json— schema every conformance report conforms to (CN-4).
- CI now runs the harness on every commit: the reference implementation must reach Core+, and the broken implementation must be rejected.
Changed
tools/signet-to-ubl.jsrefactored to export a puretoUBL(invoice)function (shared by the CLI, the harness, and the website); CLI output unchanged.
Added
tools/signet-to-ubl.js— a dependency-free reference transform that projects a SIGNET canonical Invoice into a UBL 2.1 Invoice conforming to Peppol BIS Billing 3.0 (EN 16931 compliant). Each mapping is annotated with its BT/BG reference.examples/invoice.ubl.xml— the generated Peppol BIS Billing output for the worked invoice, committed so the projection is visible without running it.tools/verify-ubl.py— parses the generated UBL and reconciles every key EN 16931 Business Term and the monetary totals against the source invoice; exits non-zero on mismatch.- CI now runs the transform and verification on every push, so "convertible to Peppol BIS" is a continuously-proven claim, not an assertion.
npm run transformandnpm run verify-ublscripts.
Notes
- This is a faithful reference projection, not a substitute for official Peppol validation. Production use should additionally run the output through the Peppol/EN 16931 XSD + Schematron validation artefacts.
Added
- Complete process layer. JSON Schema for the remaining OCDS-aligned lifecycle objects: Need, Evaluation, Award, Contract, Order, Catalogue, Obligation, and Invoice.
- EN 16931 building blocks in the foundation definitions: Unit, InvoiceLine, and VatBreakdown, with field-level mappings to EN 16931 Business Terms.
- EN 16931-mapped Invoice schema and worked example. The Invoice carries 33 EN 16931 Business Terms / Groups (BT-1…BT-158, BG-4/7/23/25), so a SIGNET invoice is convertible to Peppol BIS Billing / UBL Invoice / Factur-X. This is the structural basis for the EU ViDA cross-border e-invoicing claim.
- New worked examples:
need.json,contract.json(with embedded obligations), andinvoice.json(EN 16931-mapped, arithmetically consistent: €6,200 net + €1,302 VAT @ 21% = €7,502 payable), all CI-validated.
Fixed
- BT-mapping annotations on
$reffields are now preserved under Draft-07 by wrapping the reference inallOf(Draft-07 ignores keywords that sit beside a bare$ref). EN 16931 traceability is now structurally retained in the schema.
Added
- Foundation layer: Identifier, Party, Value, Period, Classification, Item, Credential, Document, Provenance, Score.
- Process layer (initial): SourcingEvent, Submission, Policy.
- Agent layer: SyntheticAgent, Mandate, Decision.
- Trust layer: Event, Consent.
- JSON-LD
@contextaligning to ePO, PROV, and W3C VC. - Closed and open codelists (CSV).
- Worked examples with CI validation.
Notes
- This is a working draft for community review. Field-level definitions are illustrative of the model's shape and not yet frozen.
- Targets JSON Schema Draft-07 for maximum implementer-tooling compatibility. A migration to 2020-12 will be considered before v1.0.