§14 — Offline Operation Mode v1.5
A robot in a factory basement that loses WiFi for 30 minutes should not become uncontrollable. v1.5 specifies how robots authenticate locally without registry connectivity while maintaining security boundaries.
Offline Mode Triggers
A robot enters offline mode when:
- Registry is unreachable for more than
offline_grace_s(default: 300 seconds) - DNS resolution for registry hostname fails
- All retry attempts to registry API timeout
The robot transitions back to online mode when the registry responds to a health check.
Protocol 66 Manifest — Offline Fields
GET /api/safety/manifest
{
"protocol": 66,
"rcan_version": "1.5",
"offline_mode": true,
"offline_since_s": 1842, // Seconds since entering offline mode
"clock_synchronized": true,
...
} What Is Allowed Offline
| Operation | Offline Allowed? | Condition |
|---|---|---|
| ESTOP from any source | ✅ Always | P66 invariant — no registry needed |
| Commands from same-network, same-owner | ✅ Yes | Owner JWT within exp window AND cached key matches |
| Commands using cached consent records | ✅ Yes | Consent not expired; local SQLite consent store |
| Cross-owner commands | ⚠️ Limited | Allowed up to offline_cross_owner_grace_s (default 3600s) |
| New principal authentication | ❌ Blocked | Cannot verify new JWTs without registry |
| Cross-registry consent requests | ❌ Blocked | Requires federation connectivity |
| Robot registration / RRN lookup | ❌ Blocked | Requires registry API |
Local Key Cache
Robots MUST cache the registry's public key(s) locally for offline JWT validation:
- Cache stored as JSON file:
~/.rcan/key_cache.json - Refreshed on every successful registry connection
- Maximum TTL: 24 hours (86400s)
- Cache includes the full JWKS from the registry
// key_cache.json format
{
"cached_at": 1741000000,
"ttl_s": 86400,
"registry_url": "https://rcan.dev",
"keys": [ ...JWKS keys... ]
} Offline JWT Validation
When registry is unreachable, validate JWTs against the local key cache:
- Extract
kidfrom JWT header - Look up key in local cache by
kid - Verify JWT signature against cached public key
- Verify JWT
exphas not passed - Verify JWT
audmatches this robot's RURI - If cache is expired (> 24h): reject with
OFFLINE_KEY_CACHE_STALE
Local Consent Store
Consent records MUST be persisted locally (SQLite) for offline operation:
- Store path:
~/.rcan/consent.db - Populated from Firestore/registry on each successful sync
- Used for offline consent validation when registry is unreachable
- Records are read-only offline (no new consent grants without registry)
Cross-Owner Grace Period
Cross-owner commands (commands from operators who own a different robot) are allowed for offline_cross_owner_grace_s after entering offline mode:
offline:
grace_period_s: 86400 # Cache valid for 24h offline (key cache TTL)
cross_owner_grace_s: 3600 # Cross-owner commands allowed for 1h offline
max_key_ttl_s: 86400 After cross_owner_grace_s: cross-owner commands are blocked. Same-owner commands continue as long as the key cache is valid.
Reconnection Behavior
When the registry becomes reachable again:
- Refresh key cache from registry
- Sync consent records from Firestore
- Re-authenticate all currently-active sessions (re-validate cached tokens against fresh keys)
- Transmit any audit events buffered during offline period
- Set
offline_mode: falsein Protocol 66 manifest - Log a reconnection audit event with
offline_since_sduration
See Also
- Key Rotation — JWKS format used in key cache
- Robot Identity Revocation — revocation cache staleness and quarantine mode
- §8.4 Time Synchronization — restricted mode when clock unsynchronized
- Consent Wire Protocol — offline consent blob format