Repository navigation
Conversation
SignatureRequest (d5874436-fb13-46b2-b0f1-f2882c261fa3, governance) keeps a change that needs signatures before it is written — a Delegation needing its director's grant and the delegate's consent, a board change — in the owner's vault instead of a platform database: the proposed record and its hash, one slot per needed signature, and the request's status. A grant slot holds the w3ds-grant/v1 signature that becomes the written record's authorization. A consent slot names a `consent` BindingDocument in the signer's own vault: the requesting platform creates it, the subject counter-signs (as for social_connection, the counterparty must be the subject), declining is deleting it. - ontology: signatureRequest.json; binding-document.json gets "consent" in the type enum, definitions.ConsentData and a per-type rule - evault-core: the consent type in BindingDocumentType, the GraphQL enum and both VALID_BINDING_DOCUMENT_TYPES lists; validation of ConsentData; the subject-only counter-signature rule; spec tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
andpuc23
marked this pull request as draft
October 22, 2026 09:29
… record Adds legalForm, foundingDate, iban and statutesFileUri next to legalName, registrationNumber and jurisdiction, and says that `address` is the registered address (legal seat), not a visiting address. Platforms keep these elsewhere today (eCommons CORE in its own Organization record, written by several platforms). In the Company record they are covered by the director's signature in `authorization`, so only a director can change them; in particular nobody can swap the IBAN payers see without one. All new fields are optional: existing records stay valid. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The record describes any organisation with a board (a company, a foundation, an association, a cooperative), so its human-readable name is now "Organization". Only the title and description change: the schemaId, the fields and the vault type "company" in /whois stay as they are, and nothing looks the schema up by title. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
andpuc23
marked this pull request as ready for review
October 22, 2026 09:40
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description of change
Three parts:
d5874436-fb13-46b2-b0f1-f2882c261fa3, domaingovernance), in the vault of the party the proposed record belongs toservices/ontology/schemas/signatureRequest.jsonconsent, in the signer's own vaultdefinitions.ConsentDatainservices/ontology/schemas/binding-document.json(withconsentin thetypeenum and a per-type rule), plus the eVault changes below0f9a3cb8-4a9f-4b5f-a1fa-3a4c2eb1f402) gets the organisation's full legal identity and is titled Organizationservices/ontology/schemas/company.json,docs/docs/W3DS Protocol/Company-Delegation.mdWhat it's for
Some records must not be written until specific people have signed: a Delegation needs its director's grant, and a platform may require the person receiving a role to consent; a board change, an admission or a mandate can need several people. Today the waiting state of such a change has nowhere to live in W3DS. It ends up in a platform database, so only that platform can see it, the people concerned can't prove what they agreed to, and nothing reaches their wallets.
consentBindingDocument is how a person consents: it sits in their own vault, so they keep the proof, and the eID Wallet can prompt for it exactly as it already prompts for a pendingsocial_connection(fix(eid-wallet): accept, decline or cancel a social binding from the list #1147, fix(eid-wallet): show an incoming social request on the home screen, and stop × from declining it #1164).w3ds-grant/v1signature over the proposed record, which becomes that record'sauthorizationwhen it is written. The director signs once.The first writer is Ruby (an organisation and roles platform, a fork of eCommons CORE). When @sarah, a director, puts @XOLANI into the role head:
subjectslot for Xolani (consent) and anauthorityslot for Sarah (grant).consentBindingDocument in Xolani's vault (signed with Ruby's own key as the owner signature) and posts a Message in the organisation's Chat: "@sarah wants @XOLANI to become head, signatures needed: @XOLANI, @sarah". The eVault notifies the chat's participants.createBindingDocumentSignature). Sarah signs the grant through Ruby.authorization) and marks the requestexecuted.Nothing in either part is specific to Ruby or to Delegations.
Why not an existing schema
statusisactiveorrevoked, and theirauthorizationis mandatory, so an unsigned proposal is not a valid record. They have room for one signature (the grantor's), andadditionalProperties: falserules out adding a subject's consent.256510c7…) is the closest match and the model we follow (a canonical record plus each signer's own record in their vault). But it is built around a PDF (fileUri,plaintextSha256of the document, encryption, form-field versioning), puts the canonical envelope on the initiator's vault and says process state lives in the platform database. Here the subject is a proposed record, the request belongs in the owner's vault and its state must be in the vault. Extending it would change its meaning for docusigner's existing data.Part 1: SignatureRequest
eligibleENames. "A director" is one slot listing every director. Every slot must be signed; one decline declines the request.subject,authority,approver,witness.grant(aw3ds-grant/v1signature held in the slot'sgrant, in the same shape as Role/Delegation/Companyauthorization) orconsent(aconsentBindingDocument in the signer's vault, named bybindingDocumentId).proposal.recordis the record as it will be stored apart fromauthorization,recordSha256its hash, andrecordIdthe MetaEnvelope id it will be written under, chosen in advance. A different proposal is a new request._aclreadable by the eligible signers, the requester and the owner's admins.governance(mandates and permissions), where role and board changes belong.legal(contracts and signatures) was considered; a SignatureRequest authorises a change in who may act for the owner rather than recording an agreement.Part 2: the
consentBindingDocument typedata(ConsentData):kind: "consent", astatementthe wallet shows ("Become head of Test Org, requested by @sarah"), the request it answers (requestOwnerEName,requestId,slotId), therequesterEName, and theproposalit covers (ontology,recordId,recordSha256, copied from the request). Signatures cover the BindingDocument's canonical form (stableStringify({ subject, type, data })), so a consent names exactly one request, slot and proposal and can't be reused.Owner signature: the platform that created the request (Ruby), with its own key. Counterparty: must be the subject, as for
social_connection. Declining is deleting the document, as forsocial_connection.Who may read a consent.
createBindingDocumenttakes no access policy today and stores the document readable by its subject only. The recommended shape is an optional_acloncreateBindingDocument, so the requesting organisation can read the consent from the start. Until the eVault accepts one, the platform attaches the_aclright after creating the document withupdateMetaEnvelope, acting for the subject; the eVault keeps it through later signatures. Ruby does this.Verification. The dedicated BindingDocument mutations check every signature, but the generic
updateMetaEnvelopepath does not protect BindingDocuments, nor Role, Delegation or Company: enforcing company authority on writes (#1193) was closed without merging. Anyone relying on a consent or grant therefore re-checks its signatures (for a grant,checkGrantAuthorization), as they already must for Role and Delegation.The platform's key. The eVault verifies the owner signature against the keys the Registry certifies for the signer's eName (
keyBindingCertificatesin/whois). A platform eName assigned by GitW3 starts with none. GitW3's deployment key doesn't fill the gap, since it is bound to the separate deployment eName. The platform registers a key for its own eName instead: it generates an ECDSA P-256 pair server-side, keeps the private key out of the repository, and sends the public key to its eVault withPATCH /public-key(X-ENAMEthe platform eName, a Registry token whose platform claim is that eName);/whoisthen serves a key binding certificate for it, and the platform's signatures verify.Notifications need no eVault change. The eID Wallet finds an unsigned
consentdocument in its own vault the way it finds a pendingsocial_connection(the home screen's periodic check), and the requesting platform tells the people concerned by posting a Message in the relevant Chat, for which the eVault already notifies every participant's wallet. Ruby posts "@sarah wants @XOLANI to become head. Signatures needed: @XOLANI, @sarah" in the organisation's Chat.In
binding-document.jsonthat is three edits:"consent"inproperties.type.enum;ConsentDataunderdefinitions; and anallOfentry like the existing per-type ones, so aconsentdocument'sdatamust beConsentData:{ "if": { "properties": { "type": { "const": "consent" } }, "required": ["type"] }, "then": { "properties": { "data": { "$ref": "#/definitions/ConsentData" } } } }Changes besides the ontology:
infrastructure/evault-core/src/core/types/binding-document.ts"consent"inBindingDocumentType; aBindingDocumentConsentDatainterfaceinfrastructure/evault-core/src/core/protocol/typedefs.tsconsentin the GraphQLBindingDocumentTypeenuminfrastructure/evault-core/src/core/protocol/graphql-server.ts"consent"in bothVALID_BINDING_DOCUMENT_TYPESlistsinfrastructure/evault-core/src/services/BindingDocumentService.tscase "consent"invalidateBindingDocumentData(the shape above), and inaddCounterpartySignaturethe same rule associal_connection: the counterparty must be the subjectinfrastructure/evault-core/src/services/BindingDocumentService.spec.tsNot in this PR, a follow-up for the eID Wallet:
infrastructure/eid-wallet/src/lib/utils/socialBinding.ts,pendingSocialRequest.tsand/mainshould look for unsignedconsentdocuments as well associal_connectionones, and show the consent prompt withdata.statementand the requester; Accept adds the signature, Decline deletes. Until then a platform can collect the consent signature with aw3ds://signrequest over the document's canonical form, which is what Ruby does.Part 3: Organization (formerly Company)
The organisation's full legal identity in the record
Adds four optional fields next to
legalName,registrationNumberandjurisdiction:legalFormfoundingDateformat: date)ibanstatutesFileUriw3ds://fileURIIt also says that
addressis the registered address (the legal seat), not a visiting address.Why here: platforms keep these details elsewhere today. eCommons CORE, for example, has them in its own Organization record, which several platforms write. In this record they are covered by the director's signature in
authorization, so only a director can change them. In particular, nobody can swap the IBAN payers see without a director's signature. Details people edit day to day (a display name, branding, a visiting address) stay out of it, because a board signature for every edit would be too much.The section "Company: born with its board" in
docs/docs/W3DS Protocol/Company-Delegation.mdgets a paragraph saying so.Titled "Organization"
The record describes any organisation with a board: a company, a foundation, an association, a cooperative. So its title becomes Organization, and the description notes it was titled "Company" until 2026-10. The
schemaId, the fields and the vault typecompanyin/whoisare unchanged, and nothing looks the schema up by title (the Ontology service matches titles only for the Domain schema). If reviewers prefer to keep "Company", that is its own commit and can be dropped.Issue Number
None. Builds on the Company, Role and Delegation ontologies (#1191); see the note on #1193 under Verification.
Type of change
How the change has been tested
pnpm -F=evault-core test: 27 files, 372 tests pass, including 3 new ones inBindingDocumentService.spec.ts(Neo4j test container).evault-core:tsc --noEmitclean. All 69 ontology schemas pass the draft-07 meta-schema with unique ids, and the ontology service serves both changed schemas.End to end on a local dev stack (registry, provisioner and eVault-core at
215890cplus this change, signing with the dev sandbox wallet), driven by Ruby: a director creates a Role, assigns a member, the member'sconsentdocument is created in their vault and counter-signed, and the Delegation is written with the director's grant as itsauthorization; declining and withdrawing too.checkGrantAuthorizationfrom@metastate-foundation/delegationaccepts the written Role, Delegation and revocation. 48 SignatureRequests and 8 consent documents written there validate against these schemas.Organization:
company.jsonpasses the draft-07 meta-schema. A record with every new field validates.Organization: refused are an IBAN with spaces or lower case, a founding date not in
YYYY-MM-DD, a statutes link that isn't aw3ds://fileURI, and a non-string legal form.Organization: A record without the new fields still validates, so existing Company records are unaffected.
Organization: The ontology service starts with the change and serves the schema under the title "Organization", with the four new fields.
Change checklist
checkandcheck-formathave no tasks for the changed packages)