§12 — Command Delegation and Chain of Custody v1.5
When Robot A commands Robot B on behalf of Human A, Robot B must be able to prove that Human A authorized it. Without a delegation chain, a compromised robot can issue arbitrary commands to peers with no human provenance.
delegation_chain Field
Commands sent by a robot acting on behalf of a human MUST carry a delegation_chain array in the message envelope:
{
"id": "uuid-v4",
"type": 1,
"rcan_version": "1.5",
"source": "rcan://rcan.dev/org/arm/v1/unit-001",
"target": "rcan://rcan.dev/org/delivery/v1/unit-002",
"delegation_chain": [
{
"issuer_ruri": "rcan://rcan.dev/human/craig", // Who issues this hop
"human_subject": "craig@example.com", // Human authorizing the chain
"timestamp": 1741000000,
"scope": ["control"],
"signature": "ed25519:..." // Signed by issuer's private key
},
{
"issuer_ruri": "rcan://rcan.dev/org/arm/v1/unit-001", // Robot A delegates to Robot B
"human_subject": "craig@example.com",
"timestamp": 1741000001,
"scope": ["control"],
"signature": "ed25519:..."
}
],
"payload": { "cmd": "receive_package" }
} DelegationHop Structure
| Field | Type | Description |
|---|---|---|
issuer_ruri | string (RURI) | The principal issuing this hop in the chain |
human_subject | string | The human on whose behalf the chain operates |
timestamp | float | Unix timestamp when this hop was created |
scope | string[] | Scopes being delegated at this hop |
signature | string | Ed25519 signature by issuer_ruri's private key over the hop data |
Receiver Verification Rules
- Chain length: Reject if
delegation_chain.length > 4withDELEGATION_CHAIN_EXCEEDED - Each hop signature: Verify against the issuer's public key (from registry or JWKS)
- Human subject scope: Verify that
human_subjectholds the requested scope on the target robot per R2RAM §11 - Scope chain: Each hop's scope must be ≤ the previous hop's scope (cannot escalate privileges)
- Timestamp freshness: Each hop's timestamp must be within
delegation_ttl_s(default: 3600s) - Audit: CommitmentRecord MUST serialize the full delegation chain
delegation_chain is absent and the sender is a robot (not a human), receivers MUST reject the command with MISSING_DELEGATION_CHAIN. A robot cannot command another robot without proving human authorization.
Maximum Chain Depth
Delegation chains are limited to 4 hops:
Human A → Robot A → Robot B → Robot C → Robot D ✅ (4 hops, allowed)
Human A → Robot A → Robot B → Robot C → Robot D → Robot E ❌ (5 hops, DELEGATION_CHAIN_EXCEEDED) This limit prevents unbounded trust chains and simplifies verification. Commands reaching max depth are rejected with error code DELEGATION_CHAIN_EXCEEDED.
Flat Commands (No Delegation)
When a human directly commands a robot, delegation_chain may be omitted or empty. The JWT sub claim is the implicit single-hop authorization:
// Human directly commanding robot — no delegation_chain needed
{
"type": 1,
"source": "rcan://human/craig",
"target": "rcan://rcan.dev/org/arm/v1/unit-001",
"delegation_chain": [] // or omit entirely
} §8.9 — Physical Presence Verification v1.5 SHOULD
Gap: GAP-19 — High-risk operations (ESTOP_CLEAR, maintenance mode) should require the operator to be physically present.
presence_verified Field
High-risk SAFETY commands SHOULD include presence evidence:
{
"type": 6,
"payload": {
"cmd": "ESTOP_CLEAR",
"presence_verified": true,
"proximity_m": 2.1, // Estimated distance from robot (meters)
"presence_token": "eyJ..." // Signed presence token (valid for 300s)
}
} Presence Token
A presence token is issued by the robot when a human proves physical proximity:
- QR code scan: Robot displays OTP QR code; human scans it with RCAN app
- BLE proximity: RSSI threshold check (typically <5m)
- UWB challenge-response: Ultra-wideband ranging (±30cm accuracy)
Presence tokens are valid for 300 seconds and are single-use per ESTOP_CLEAR command.
physical_presence_required Flag
Operators can mark specific scope definitions as requiring physical presence:
safety:
estop_clear_requires_presence: true # ESTOP_CLEAR blocked without presence token When physical_presence_required: true, ESTOP_CLEAR commands missing a valid presence_token MUST be rejected. ESTOP itself is never blocked.
Audit Trail
CommitmentRecords for delegated commands MUST include the full delegation_chain. This enables audit queries like:
- "Show all commands issued by Robot A on behalf of Craig"
- "Show all R2R commands in the last 24 hours with their human subjects"
- "Which robots did Robot A command, and who authorized it?"
Error Codes
| Code | Cause |
|---|---|
DELEGATION_CHAIN_EXCEEDED | Chain depth > 4 |
DELEGATION_VERIFICATION_FAILED | Hop signature invalid |
MISSING_DELEGATION_CHAIN | Robot sender missing chain |
INSUFFICIENT_SCOPE_IN_CHAIN | Human subject lacks requested scope on target |
SCOPE_ESCALATION_IN_CHAIN | Hop grants wider scope than previous hop |
PRESENCE_TOKEN_REQUIRED | physical_presence_required but no token |
PRESENCE_TOKEN_EXPIRED | Presence token > 300s old |
See Also
- Consent Wire Protocol — consent is a prerequisite for cross-robot delegation
- Robot Identity Revocation — revoked robots cannot issue delegation chains
- Key Rotation — key_id links delegation hop signatures to specific keys
- Authentication — R2RAM scope hierarchy