Skip to content

Move APNs registration state to shared SQLite #108535

Description

@steipete

Summary

Move APNs registration runtime state from push/apns-registrations.json into the shared OpenClaw SQLite state database.

Problem to solve

APNs device tokens and relay grants are durable runtime state, but the current store is a JSON sidecar. Whole-file rewrites have only process-local serialization, and the file remains outside the database-first state model. Removing the runtime reader without an explicit migration would strand shipped registrations; retaining a fallback would let stale JSON resurrect registrations that SQLite has replaced or deleted.

Proposed solution

  • Make apns_registrations the only runtime read/write path, using the shared Kysely-backed state database.
  • Persist registration deletions as tombstones until the retired JSON source has a migration receipt.
  • Add an exclusive openclaw doctor --fix migration that safely claims the legacy file, streams and validates every shipped record shape, preserves newer canonical rows, suppresses deleted rows, records a transactional receipt, verifies the result, and then removes the legacy file.
  • Treat a receipt as authoritative so recreated or interrupted legacy files are cleanup-only and cannot resurrect state.
  • Keep APNs delivery/authentication separate from the storage owner.

Alternatives considered

  • Dual-write or read-through fallback: rejected because it leaves two authorities and creates stale-state resurrection races.
  • Discard the JSON file: rejected because APNs registrations are persistent user state required for iOS wake and approval delivery.
  • Dedicated APNs database: rejected because the shared state database already owns global runtime state and the record volume/lifecycle fits it.

Impact

Affected: Gateways with paired iOS devices using direct or relay APNs registrations.

Severity: High during upgrade if registration continuity or invalidation semantics are lost.

Frequency: One migration per existing state directory; all later reads and writes use SQLite.

Consequence: Correct migration preserves push delivery across restart. The database-only runtime removes whole-map rewrites and prevents retired JSON from reviving invalidated device registrations.

Evidence/examples

  • Current runtime store: src/infra/push-apns.ts
  • Shared state schema: src/state/openclaw-state-schema.sql
  • Database-first contract: docs/refactor/database-first.md

Additional information

Implementation and migration design were produced with AI assistance and will use focused upgrade tests, changed gates, and exact-head CI before landing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestmaintainerMaintainer-authored PR

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions