Skip to content

Add registration property. Update UNTP example to use it. - #142

Merged
msporny merged 2 commits into
mainfrom
add-registration
Oct 31, 2026
Merged

msporny merged 2 commits into
mainfrom
add-registration

Conversation

@msporny

@msporny msporny commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

Attempt to address issue #140 by adding a registration property that allows re-use of another ecosystem's registration vocabulary such as UNTP, Digital Product Passport, schema.org Certification, or similar ecosystem registration schema.


Preview | Diff

@philarcher philarcher left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The key person needed to review this is @onthebreeze. From my POV it looks good and I am grateful, @msporny, for your work on doing this. Thank you. But I am not in a position to record an approval until Steve has had a look.

@onthebreeze

Copy link
Copy Markdown
Contributor

looks good. The group may wish to add some properties to the registration object. Here's what we'll be publishing to UNTP DIA page very soon

Screenshot 2026-10-19 at 10 31 45 pm

@msporny

msporny commented Oct 19, 2026

Copy link
Copy Markdown
Member Author

@onthebreeze wrote:

Here's what we'll be publishing to UNTP DIA page very soon

Excellent, step in the right direction, IMHO.

Forgive the rest of this, as it's pedantic from a data modelling perspective, but I got tripped up on it while I was putting this PR together.

In the DIA work, it feels like RegisteredIdentity should really be Registration, with the following changes to the data model:

  • registerType -> this might need to go in a register relationship?
  • register -> Register(class)
    • registerType -> type
    • controlType
    • geoBoundary
    • recognitionScope

In the end, where we could end up is this:

  • A RecognizedEntity has one or more registrations
  • A registration expresses the information about the registration (like registration identifier, registered name, etc.)
  • A registration is associated with a Register (the thing upon which the registration is recorded)
  • A Register describes its type, scope, geoBoundary, legal authority, etc.

I haven't been able to think through this change in detail, but hope you can think more deeply about it @onthebreeze as we try to see if this change is going to work for the DIA and metrology use cases.

... and to make sure we're tying up loose ends here. @onthebreeze do you see comparison of a registeredId in a Recognized Entity VC against a CommercialInvoice to be something that is market vertical specific (that is, implemented in market vertical specific software) OR do you expect that the FieldMatch/JSONata solution needs to work for this as well?

For example, attempting to figure out if a registration geoBoundary applies to a particular transaction involving a CommercialInvoice is something that JSONSchema, FieldMatch, nor JSONata can solve. You need a programming language to do those sorts of comparisons and therefore, that functionality is out of scope for the RecognizedEntity spec. The best we can do is provide data upon which a complex validation algorithm can operate. @philarcher @paulfdietrich @dlongley -- this is the part where I don't know if the GS1 use case overlaps with the DIA/Conformity Assessment/metrology use case. It's when things like geoBoundary and scope are a part of the use case where I become concerned that we cannot provide a generalized solution to that challenge.

@onthebreeze

Copy link
Copy Markdown
Contributor

The property name is registration - it just reuses a class definition called RegisteredIdentity.

So, for a business registration, it might look like this

Business registration

"credentialSubject": {
  "type": [
    "RecognizedEntity"
  ],
  "id": "did:web:sample-refinery.example.com",
  "name": "Sample Copper Refinery Ltd",
  "registration": [
    {
      "type": [
        "RegisteredIdentity"
      ],
      "id": "https://sample-business-register.example.com/registers/business/entities/BR-00042187",
      "registeredId": "BR-00042187",
      "registeredDate": "1985-06-15",
      "idScheme": {
        "type": [
          "IdentifierScheme"
        ],
        "id": "https://sample-business-register.example.com/registers/business",
        "name": "Sample Business Register"
      },
      "registerType": "business",
      "controlType": "self",
      "recognitionScope": [
        {
          "type": [
            "RecognitionScope"
          ],
          "id": "https://sample-business-register.example.com/entity-types/public-company-limited-by-shares",
          "name": "Public Company Limited by Shares"
        }
      ]
    }
  ]
}

But for a trademark registraiotn perhaps more like this - note that the ID of the think in the registration is the trademark ID - not the same as the ID of the subject of the recognised entity. It's basncailly saying that the registrar recognizes that the recognised entity that is the controller of the did is also the owber / controller of the trademark.

"credentialSubject": {
  "type": [
    "RecognizedEntity"
  ],
  "id": "did:web:sample-battery.example.com",
  "name": "Sample Battery Manufacturer Ltd",
  "alsoKnownAs": {
    "id": "https://sample-business-register.example.com/registers/business/entities/BR-00088214",
    "name": "Sample Battery Manufacturer Ltd"
  },
  "registration": [
    {
      "type": [
        "RegisteredIdentity"
      ],
      "id": "https://sample-ip-office.example.com/registers/trademark/marks/TM-0024001234",
      "registeredId": "TM-0024001234",
      "registeredName": "SampleCell",
      "registeredDate": "2022-03-10",
      "idScheme": {
        "type": [
          "IdentifierScheme"
        ],
        "id": "https://sample-ip-office.example.com/registers/trademark",
        "name": "Sample Trademark Register"
      },
      "registerType": "trademark",
      "controlType": "owner",
      "recognitionScope": [
        {
          "type": [
            "RecognitionScope"
          ],
          "id": "https://sample-ip-office.example.com/goods-classes/9",
          "name": "Goods Class 9 \u2014 electrical apparatus"
        }
      ]
    }
  ]
}

@onthebreeze

Copy link
Copy Markdown
Contributor

goeboundary is a bit of an odd ball and I'm not even sure we should have it - but it's for the special case of a land register - and it describes the boundary of the registered Lot.

Invoice rules would probably need to check that

  • The subject did of the registered entity vc matches the issuer did of the invoice (that's the cryptographic chain)
  • the seller business number in the invoice matches the RegisteredId in the registration (that's the legal entity match)

@msporny

msporny commented Oct 19, 2026

Copy link
Copy Markdown
Member Author

@onthebreeze we might be talking past each other on the remaining 10% that I'm trying to ensure we're aligned on... let me try again, but this time by asking a question:

Why is "registerType" associated with the "RegisteredIdentity" instead of the "IdentifierScheme"? That doesn't feel right to me. I would expect registerType to exist as a parallel property to "name": "Sample Business Register"... and why is it called IdentifierScheme, and not Register when the object is clearly a register... afterall, it's name is literally "Sample Business Register"?

You seem to be hanging properties off of the RegisteredIdentity that are really properties of the Register (currently called IdentifierScheme).

@onthebreeze

Copy link
Copy Markdown
Contributor

I think the rationale for that modelling of register is called "too late, too tired, too many tasks". Thanks for your feedback - shouldn't be on you to fix my poor data modelling.

"credentialSubject": {
  "type": [
    "RecognizedEntity"
  ],
  "id": "did:web:sample-refinery.example.com",
  "name": "Sample Copper Refinery Ltd",
  "registration": [
    {
      "type": [
        "RegisteredIdentity"
      ],
      "id": "https://sample-business-register.example.com/registers/business/entities/BR-00042187",
      "registeredId": "BR-00042187",
      "registeredDate": "1985-06-15",
      "register": {
        "type": [
          "Register"
        ],
        "id": "https://sample-business-register.example.com/registers/business",
        "name": "Sample Business Register",
        "registerType": "business"
      },
      "controlType": "self",
      "recognitionScope": [
        {
          "type": [
            "RecognitionScope"
          ],
          "id": "https://sample-business-register.example.com/entity-types/public-company-limited-by-shares",
          "name": "Public Company Limited by Shares"
        }
      ]
    }
  ]
}

@msporny

msporny commented Oct 19, 2026

Copy link
Copy Markdown
Member Author

I think the rationale for that modelling of register is called "too late, too tired, too many tasks".

lol -- I suffer from that particular affliction as well. Thanks for being open to change this part of the model. I may have some other suggestions during the call tomorrow around controlType and registrationScope and where they go.

As an aside, I think this speaks positively to the direction proposed by this PR as well. That is, it's not to the VCWG RE Task Force's domain to specify how registration happens and is expressed, that is the purview of the UNTP folks (and possibly other organizations that specialize in that sort of thing -- the business register organizations of the world, not W3C). Our job in the VCWG RE TF is to just enable registration to be expressed in a way that is supportive of the use cases of the various communities.

For example, perhaps WCO has a different registration expression mechanism... or they re-use UNTP's mechanism... either way, the decision is made among a group of people that focus on that sort of thing, rather than the VCWG. IOW, you could reject the change suggestions, and that would be perfectly fine, as it's not our business to tell you how to model your data (other than we want UNTP to be successful and getting the data model aligned with best practices is a part of that).

@onthebreeze onthebreeze left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me - see long discussion in the PR conversation thread. The group may wish to consider some (not all) of the recognition object properties proposed by UNTP DIA in the W3C spec. But even of not, this is the right shape for handling formal registrations using the recognized entity credential.

Comment thread index.html
the properties of a `RegisteredIdentity` from the UNTP Digital Identity Anchor
[[?UNTP-DIA]]: `registeredId` holds the registration number, `idScheme`
identifies the register that assigned it, `registerType` states that the
register is a business register, and `registrationScopeList` identifies the

@dlongley dlongley Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EDIT: I see there's conversation about this now.

Does this have to be a "list"? Perhaps this is just a URL that describes the registration "scope":

Suggested change
register is a business register, and `registrationScopeList` identifies the
register is a business register, and `registrationScope` identifies the

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a part of the UNTP vocabulary, so we don't have any control over it. It is registrationScopeList over there. @onthebreeze will have to change it if they want to take your change (which I agree with).

@philarcher philarcher left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having heard the discussion with Steve, I fully support this being merged. Thank you @msporny and @onthebreeze

@longpd longpd left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good, with the term mods to be done later.

Comment thread index.html Resolved
Comment thread index.html Resolved
Comment thread index.html Resolved
Comment thread index.html Resolved

@TallTed TallTed left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

works for me, modulo some editorial tweaking

Co-authored-by: Ted Thibodeau Jr <tthibodeau@openlinksw.com>
@msporny

msporny commented Oct 31, 2026

Copy link
Copy Markdown
Member Author

Normative, multiple reviews, changes requested and made, no objections, merging.

@msporny
msporny merged commit 87a5dbe into main Oct 31, 2026
2 checks passed
@msporny
msporny deleted the add-registration branch October 31, 2026 21:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants