Proposal 024: Capability Passports and Network Ledger Delegation¶
Based on:
- doc/project/40-proposals/014-node-transport-and-discovery-mvp.md
- doc/project/40-proposals/017-organization-subjects-and-org-did-key.md
- doc/project/40-proposals/021-service-offers-orders-and-procurement-bridge.md
- doc/project/40-proposals/023-federated-offer-distribution-and-catalog-listener.md
- doc/project/20-memos/participant-assurance-levels.md
- doc/project/60-solutions/node.md
Status¶
Draft
Date¶
2026-03-31
Executive Summary¶
The current Node runtime can trust local sovereign operators and can project participant assurance levels, but it cannot yet delegate infrastructure capabilities from one trusted Node to another through one portable, verifiable artifact.
This proposal introduces capability-passport.v1 as that general delegation
artifact.
The decisions of this proposal are:
- infrastructure capabilities delegated to other Nodes must be expressed as a
signed
capability-passport.v1artifact rather than as ad-hoc config, - passport signing authority belongs to a local participant whose derived
assurance level is
sovereign-operator, - the signing format is deterministic canonical JSON with the
signaturefield omitted from the signed payload, network-ledgeris the first concrete delegated infrastructure capability,- network settlement must use a dedicated async adapter layer rather than
extending the synchronous local
SettlementLedgertrait, - hard-MVP discovery for delegated infrastructure capabilities is static config pinned by a trusted sovereign issuer, not gossip or dynamic marketplace discovery.
- capability identifiers must distinguish formal global names from identity-anchored sovereign names so private or deployment-local capability namespaces do not collide.
This keeps the stratification clean:
- local settlement remains a small synchronous write/read core,
- network settlement becomes a separate async adapter boundary,
- trust delegation is modeled once and can later be reused for
escrow,oracle, or other attached infrastructure roles.
Context and Problem Statement¶
The current settlement rail is deployment-local. Each Node rebuilds ORC account
balances from its own append-only LedgerFact stream and treats that local
ledger as the source of truth.
That is sufficient for hard-MVP single-deployment operation, but not for a multi-Node shape where one Node should act as a trusted infrastructure service for others, such as:
- a shared network ledger,
- a settlement escrow,
- a dispute oracle,
- or any future bounded infrastructure role.
Without one explicit delegation artifact:
- Node-to-Node trust for infrastructure roles lives in configuration folklore,
- remote capabilities cannot be audited as signed facts,
- the same trust problem will be re-solved separately for every role.
The current transport and identity proposals already define:
- canonical
node:did:key:..., - canonical
participant:did:key:..., - sovereign operators as a special trust class orthogonal to ordinary identity assurance.
What is missing is one general artifact that says:
this sovereign operator, on this issuing Node, delegates this infrastructure capability to that target Node, under this scope, until this expiry.
Goals¶
- Define
capability-passport.v1as the general signed delegation artifact for infrastructure capabilities. - Freeze the canonical signing rules for the passport.
- Freeze the minimum verification algorithm used by receiving Nodes.
- Define
network-ledgeras the first concrete capability delegated through a passport. - Freeze
NetworkLedgerAdapteras an async boundary distinct from the synchronous local settlement trait. - Freeze static-config bootstrap for the first hard-MVP network-ledger deployment profile.
- Freeze the sovereign capability-id syntax and the corresponding wire- advertisement projection.
Non-Goals¶
- This proposal does not define dynamic capability discovery, gossip, or marketplace-based routing for infrastructure roles.
- This proposal does not define the message format or request/response framing for remote settlement operations. It only freezes the delegation artifact, the adapter boundary, and the transport choice (peer channel). The ledger wire protocol — typed message pairs, correlation IDs, and serialization contract — is a separate future specification.
- This proposal does not redefine
node-identity.v1or participant/org identity contracts. - This proposal does not define organization-level multisig issuance of passports. One sovereign operator is sufficient for hard-MVP.
- This proposal does not define passport transparency logs or revocation gossip. Revocation is local-policy driven in this phase.
Decision¶
1. capability-passport.v1 as the General Delegation Artifact¶
Infrastructure capabilities delegated to another Node MUST be expressed as one portable signed artifact:
schema = "capability-passport.v1"passport_id = "passport:capability:..."node_id = "node:did:key:..."of the target Node receiving the capabilitycapability_id = "network-ledger"or another stable capability namescope = { ... }capability-specific parametersissued_atRFC 3339expires_atRFC 3339 ornullissuer/participant_id = "participant:did:key:..."issuer/node_id = "node:did:key:..."revocation_ref = null | "node:did:key:..."signature = { "alg": "ed25519", "value": "..." }
The passport is an auditable delegated fact. It does not itself create trust out of nothing. Trust derives from local policy that recognizes the issuing participant as a sovereign operator and accepts its delegation authority.
2. Signing Authority Belongs to Sovereign Operators¶
Only a participant whose derived assurance level is sovereign-operator may
issue a capability passport.
This does not mean that IAL5 replaces ordinary identity proofing. It means
that infrastructure delegation is governed by software-pinned sovereign trust,
not by phone or government-ID attestation.
Issuer verification therefore proceeds in two stages:
- parse
issuer/participant_idfrom the passport, - check that the local Node policy treats that participant as a sovereign operator.
If the issuer is not sovereign under local policy, the passport MUST be rejected even if the signature is cryptographically valid.
3. Canonical Signing Format¶
The signed bytes are the deterministic UTF-8 bytes of the passport encoded as canonical JSON with:
- object keys sorted lexicographically,
- arrays left in original order,
- no insignificant whitespace,
- the top-level
signaturefield omitted entirely from the canonical payload.
The signature algorithm is Ed25519.
The signing and verification algorithm is:
- clone the passport payload without
signature, - serialize it into canonical JSON,
- sign those bytes with the issuer participant's Ed25519 key,
- encode the signature as base64url without padding,
- store it under
signature.value, - set
signature.alg = "ed25519".
The verifier repeats the same canonicalization and verifies the Ed25519
signature against the public key recoverable from issuer/participant_id.
4. network-ledger as the First Delegated Infrastructure Capability¶
The first concrete use of capability-passport.v1 is the network-ledger
capability.
Semantics:
- the target Node named in
node_idis authorized to act as a settlement ledger authority for the receiving deployment profile, - that Node's local
LocalOrcLedgerremains the actual source of truth for balances and holds, - remote Nodes interact with it through a network adapter boundary rather than through their own local ledger state.
The capability-specific scope for network-ledger MAY be empty in hard-MVP.
Future phases MAY add fields such as:
- allowed account namespaces,
- top-up policy refs,
- maximum hold lifetime,
- accepted receipt classes.
Receivers MUST tolerate unknown scope keys and MUST validate only the fields
they understand.
4a. Sovereign Capability Identifiers¶
Capability ids now distinguish two classes:
- formal global ids without
@, such asnetwork-ledger, - sovereign ids anchored in an identity, such as
audio-transcription@participant:did:key:z....
A sovereign id may also be informal, indicated by a leading ~ on the
capability name:
~audio-transcription@participant:did:key:z...
This gives three stable wire-level intentions:
| Form | Meaning |
|---|---|
network-ledger |
formal global capability id |
audio-transcription@participant:did:key:... |
sovereign formal capability |
~audio-transcription@participant:did:key:... |
sovereign informal capability |
Rules:
- formal capability ids MUST NOT contain
@, - sovereign capability ids MUST contain exactly one
@, - the identity suffix after
@is the anchor and may currently beparticipant:did:key:...,node:did:key:..., ororg:did:key:..., - the
~informal marker applies only to sovereign capability names.
This preserves backward compatibility for all existing formal ids while letting operators or organizations anchor private capability families in their own identity instead of the global bare-name namespace.
4b. Wire Advertisement Projection for Sovereign Capabilities¶
Capability passports keep the full sovereign id, but capability advertisements use a shorter wire name:
audio-transcription@participant:did:key:z...advertises assovereign/audio-transcription,~audio-transcription@participant:did:key:z...advertises assovereign-informal/audio-transcription.
Because the wire name alone is not enough to reconstruct the full sovereign
capability id, CapabilityAdvertisementV1 must also carry:
anchor_identities = { "audio-transcription": "participant:did:key:z..." }
Receivers therefore interpret sovereign wire advertisements from the pair:
- short wire name in
capabilities/core, - matching anchor entry in
anchor_identities.
Formal well-known capabilities still use their stable mapped wire names such as
core/network-ledger or role/offer-catalog. Unknown formal capabilities may
be advertised as bare formal names without @.
5. Async NetworkLedgerAdapter Boundary¶
The synchronous local settlement trait is intentionally not extended for remote operations.
Instead, network settlement is modeled as a separate async adapter boundary:
#[async_trait]
pub trait NetworkLedgerAdapter: Send + Sync {
async fn balance(&self, account_id: &AccountId) -> Result<OrcBalance, LedgerError>;
async fn submit_hold(&self, spec: HoldSpec) -> Result<HoldId, LedgerError>;
async fn release_hold(&self, hold_id: &HoldId) -> Result<(), LedgerError>;
async fn apply_top_up(
&self,
receipt: GatewayReceiptRecord,
) -> Result<TopUpApplyOutcome, LedgerError>;
}
Hard-MVP includes two implementations:
LocalNetworkLedgerAdapter— delegates to the localLocalOrcLedger,RemoteNetworkLedgerAdapter— talks to a trusted ledger Node over the existing inter-node WebSocket peer channel, not a separate HTTP service.
Ledger operations are expressed as typed message pairs (request + response)
on an established peer session. The peer channel is the only transport surface
for network ledger operations. This avoids a second port, reuses existing peer
authentication, and keeps capability routing within the capability model:
the network-ledger capability is announced in CapabilityAdvertisementV1,
the passport is verified post-handshake via capability-passport-present.v1,
and ledger messages flow on the same connection.
The local settlement write path remains append-only and synchronous inside one Node. The network adapter is the layer that absorbs latency, retries, and partial failure.
6. Static Config Discovery for Hard-MVP¶
The initial network-ledger deployment profile uses static configuration:
[settlement]
mode = "network"
[settlement.network_ledger]
node_id = "node:did:key:z..."
endpoint = "wss://ledger.example/peer"
passport = "path/to/capability-passport.v1.json"
The endpoint field is the WebSocket peer listener address of the target
ledger Node — the same address type carried in node-advertisement.v1
endpoint entries. It is not an HTTP API address. Ledger operations are sent
as typed messages on the peer session established to that address.
At daemon startup the Node MUST:
- load the passport,
- verify the signature,
- verify the issuer participant is sovereign under local policy,
- verify
capability_id == "network-ledger", - verify that the target
node_idmatches the configured remote ledger node, - reject startup if verification fails.
This keeps failure explicit and early. If the remote ledger passport cannot be
trusted, the Node must not start in settlement.mode = "network".
Proposed Artifact Shape¶
capability-passport.v1¶
Minimum fields:
schemapassport_idnode_idcapability_idscopeissued_atexpires_atissuer/participant_idissuer/node_idrevocation_refsignature
Example:
{
"schema": "capability-passport.v1",
"passport_id": "passport:capability:network-ledger:01hznx...",
"node_id": "node:did:key:z6MkTargetLedgerNode",
"capability_id": "network-ledger",
"scope": {},
"issued_at": "2026-03-31T19:20:00Z",
"expires_at": null,
"issuer/participant_id": "participant:did:key:z6MkSovereignOperator",
"issuer/node_id": "node:did:key:z6MkIssuerNode",
"revocation_ref": null,
"signature": {
"alg": "ed25519",
"value": "kYcC7xR8..."
}
}
Verification Rules¶
A receiver MUST reject the passport if any of the following holds:
- the payload does not parse,
- required fields are empty,
schema != "capability-passport.v1",passport_iddoes not use thepassport:capability:prefix,signature.alg != "ed25519",- the signature does not verify against
issuer/participant_id, - the issuer is not sovereign under local policy,
expires_atis present and already elapsed,- the passport's
capability_iddoes not match the role being configured.
Receivers MAY additionally reject passports by local policy, such as:
- disallowed
issuer/node_id, - disallowed
scope, - explicitly revoked
passport_id, - mismatched endpoint-to-node mapping.
Implementation Notes¶
- A host capability such as
capability.passport.signis a suitable operator interface for passport issuance. - A host capability such as
capability.passport.verifyis a suitable diagnostic surface for operators before startup or deployment. - The canonical JSON encoder should live in a small auditable crate rather than inside the daemon.
- Passport signing should use the participant signing key, not the Node infrastructure signing key, because the delegating authority belongs to the sovereign participant role.
RemoteNetworkLedgerAdapterconnects to the target Node's peer listener over WSS and exchanges typed ledger message pairs on the established session. TheRemoteLedgerClienttrait MUST be async to support the correlation-ID request/response pattern over a message-oriented connection.- Loopback operation (one Node acting as both ledger server and client) is a valid and recommended development configuration. The daemon dials its own peer endpoint; Tokio handles server and client tasks independently, so no deadlock occurs.
Consequences¶
Positive¶
- One auditable mechanism can later serve
network-ledger,escrow,oracle, and similar roles. - Trust in remote infrastructure roles becomes explicit and exportable.
- The local settlement core remains small and synchronous.
- Remote settlement enters the system through a narrow async adapter boundary.
Negative¶
- Passport issuance introduces another operator-visible artifact to manage.
- Static config is operationally manual until dynamic discovery arrives.
- Revocation remains local-policy driven in hard-MVP.
Alternatives Considered¶
Extend SettlementLedger for remote calls¶
Rejected. Remote settlement has different failure modes and latency than the local append-only ledger core. Mixing both into one synchronous trait would smear network concerns across the local settlement write path.
Reuse generic peer capability advertisement¶
Rejected for this phase. Advertisements are discovery-oriented and ephemeral, while capability passports are governance-oriented and signed for durable trust. The two artifacts serve different roles.
Trust remote infrastructure only by endpoint URL¶
Rejected. Endpoint-only trust is operationally weak and not portable. A signed passport ties capability delegation to canonical participant and Node identity.
Open Questions¶
- Should future revocation use an append-only
capability-passport-revocationfact or a short-lived denylist cache? - Should
scopefornetwork-ledgerstay opaque longer, or should the first hard-MVP include explicit account namespace constraints? - Should future multi-sig issuance be modeled as multiple signatures on one passport or as a separate endorsement bundle?