§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.

Protocol 66 Invariant: Offline ESTOP from same-network owner is ALWAYS accepted, provided the cached key matches. Registry connectivity is never required to halt a robot.

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

OperationOffline 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:

  1. Extract kid from JWT header
  2. Look up key in local cache by kid
  3. Verify JWT signature against cached public key
  4. Verify JWT exp has not passed
  5. Verify JWT aud matches this robot's RURI
  6. 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:

  1. Refresh key cache from registry
  2. Sync consent records from Firestore
  3. Re-authenticate all currently-active sessions (re-validate cached tokens against fresh keys)
  4. Transmit any audit events buffered during offline period
  5. Set offline_mode: false in Protocol 66 manifest
  6. Log a reconnection audit event with offline_since_s duration

See Also