Skip to content

[Feature]: Gateway — bridge DeviceRegistry ↔ NodeRegistry by device_id #6497

@theonlyhennygod

Description

@theonlyhennygod

Summary

Bridge the two existing registries so the gateway can answer one query: "Is the Mac with device_id X online and does it have capability Y?" Currently DeviceRegistry (SQLite, persistent identity) and NodeRegistry (in-memory, WS capability dispatch) don't talk to each other.

Problem

  • DeviceRegistry persists pairing identity but has no concept of online/offline beyond last_seen (which only updates on HTTP requests).
  • NodeRegistry has live WS-based capability dispatch but is ephemeral — no persistence, and uses a separate node_id from the device_id.
  • The agent on the gateway has no single source of truth: "send this command to the Mac" requires consulting both, and there's no guarantee they refer to the same paired entity.

Proposal

  • When a /ws/nodes WebSocket authenticates with a device's bearer token, treat the device_id == node_id.
  • Schema migration on the devices table:
    • online_since TEXT (RFC3339) — non-null when the device has an active WS connection
    • node_id TEXT — populated from the device's UUID on first WS connection
    • capabilities sync from the WS register message (overrides the HTTP-pushed list from this branch's v1)
  • On /ws/nodes register: look up device by token_hash, set online_since = now(), store advertised capabilities.
  • On WS disconnect: clear online_since, keep the row.
  • New gateway helper device_registry::is_online(device_id) -> bool and device_registry::find_online_with_capability(cap) -> Option<DeviceInfo> for the agent dispatcher to use.

Files

  • crates/zeroclaw-gateway/src/api_pairing.rs — schema migration, new fields, helpers
  • crates/zeroclaw-gateway/src/nodes.rs — bridge logic in the WS handler
  • crates/zeroclaw-gateway/src/lib.rs — AppState wiring

Acceptance

  • Existing devices migrate cleanly (additive ALTER TABLE).
  • Mac connects to /ws/nodes with bearer token → its device row gets online_since populated and capabilities synced.
  • Mac kills the connection → online_since clears within ~5s; row persists.
  • Two device_registry regression tests prove migration + bridge logic.

Related

  • Depends on the v1 capability sync from feat/desktop-onboarding.
  • Sibling issue: persistent NodeClient on the desktop side (separate ticket).
  • Capability handlers live in their own ticket (separate).

Metadata

Metadata

Assignees

No one assigned

    Labels

    desktopDesktop app (Tauri) — menu bar, dashboard parity, macOS integrationsenhancementNew feature or requestgatewayAuto scope: src/gateway/** changed.priority:p1High priorityrisk: highAuto risk: security/runtime/gateway/tools/workflows.runtimeAuto scope: src/runtime/** changed.securityAuto scope: src/security/** changed.status:acceptedRFC or work item accepted and ratified by the team.status:no-staleExempt from the 60-day stale auto-close policy.tauriTauri shell, native bindings, build/packaging

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Backlog

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions